From 4ba6b8312c7d69492496e334db0a85e747748f57 Mon Sep 17 00:00:00 2001 From: Paxton Hare Date: Thu, 15 Nov 2012 13:12:07 -0500 Subject: [PATCH] cleaned up the help system added the ability to randomly generate the app-user password added a method to load individual files or folder into the db code cleanup added warning for older versions of ruby Issue #38 - --force now works --- README.mdown | 26 +- deploy/lib/Help.rb | 420 +++++++++------ deploy/lib/MLClient.rb | 1 - deploy/lib/RoxyHttp.rb | 1 - deploy/lib/framework.rb | 106 ++-- deploy/lib/ml.rb | 196 +++---- deploy/lib/server_config.rb | 730 ++++++++++++-------------- deploy/lib/util.rb | 55 +- deploy/lib/xcc.rb | 237 ++++----- deploy/lib/xquery/setup.xqy | 258 ++++----- deploy/sample/build.sample.properties | 5 + deploy/sample/ml-config.sample.xml | 2 +- 12 files changed, 1023 insertions(+), 1014 deletions(-) diff --git a/README.mdown b/README.mdown index 46ecede7..39bcd741 100644 --- a/README.mdown +++ b/README.mdown @@ -1,6 +1,9 @@ # Roxy Roxy (RObust XQuerY Framework) is a lightweight framework for quickly developing well-structured, easily maintained XQuery applications. Roxy was heavily inspired by Ruby On Rails and CakePHP. +## Getting Help +To get help with Roxy, subscribe to the [Roxy mailing list](http://developer.marklogic.com/mailman/listinfo/roxy, Roxy mailing list). + ## Components ### Roxy Deployer Roxy Deployer makes managing MarkLogic application easy. Simply edit a few configuration files and you have full access to create and deploy applications to MarkLogic servers, local or remote. Roxy Deployer is written in Ruby and is easily extended to add additional functionality. @@ -15,6 +18,7 @@ What good is your code if it doesn't work? Testing is paramount to the developme * MarkLogic: * MarkLogic 4.x - You need the **Docs** appserver running on port 8000 - this port can be overridden in build.properties * MarkLogic 5.x - You need the **Manage** appserver running on port 8002 - this port can be overridden in build.properties + * MarkLogic 6.x - You need the **Manage** appserver running on port 8002 - this port can be overridden in build.properties * [Ruby](http://www.ruby-lang.org/en/) - Required for Roxy Deployer only. * [Java (jdk)](http://www.oracle.com/technetwork/java/javase/downloads/index.html) - Only if you wish to run the Roxy Deployer [XQSync](http://developer.marklogic.com/code/xqsync, XQSync) or [RecordLoader](http://developer.marklogic.com/code/recordloader, RecordLoader) commands. @@ -36,25 +40,25 @@ This section describes the quickest way to get started using Roxy. 3. Modify deploy/build.properties with your application's settings. - \# Username to authenticate to ML + \# Username to authenticate to ML user=your-ml-admin-username - \# password for ML authentication + \# password for ML authentication password=your-ml-admin-password - \# the authentication type for the appserver (digest|basic|application-level) + \# the authentication type for the appserver (digest|basic|application-level) authentication-method=application-level - \# the default user to authenticate with. defaults to nobody + \# the default user to authenticate with. defaults to nobody default-user=nobody - \# the root path of your modules. Use this to override the modules db and use your filesystem location + \# the root path of your modules. Use this to override the modules db and use your filesystem location modules-root=/the/path/to/your/files/on/the/filesystem \# either 'filesystem' or 'name of db' app-modules-db=filesystem - \# Specify the server(s) you wish to deploy to here. This tutorial assumes you are using localhost. - local-server=localhost - \#dev-server= - \#cert-server= - \#prod-server= + \# Specify the server(s) you wish to deploy to here. This tutorial assumes you are using localhost. + local-server=localhost + \#dev-server= + \#cert-server= + \#prod-server= - + ### Configure MarkLogic Server *This step is only needed when database configurations have changed or on a fresh install. In most cases you will not need to restart your server.* diff --git a/deploy/lib/Help.rb b/deploy/lib/Help.rb index 6d8ae635..c7538507 100644 --- a/deploy/lib/Help.rb +++ b/deploy/lib/Help.rb @@ -1,275 +1,355 @@ class Help + def self.usage + <<-DOC.strip_heredoc + + Usage: ml COMMAND [ARGS] + + Deployment Commands: + init Creates configuration files for you to customize + initcpf Creates cpf configuration files for you to customize + info Return settings for a given environment + bootstrap Configures your application on the MarkLogic server + wipe Remove your configuration from the MarkLogic server + restart Restart your MarkLogic server + deploy Loads modules, data, cpf configuration into the server + load Loads a file or folder into the server + clean Removes all files from the cpf, modules, or content databases + info Prints the configuration information + test Runs xquery unit tests + recordloader Runs RecordLoader + xqsync Runs XQSync + corb Runs Corb + + Roxy MVC Commands: + create Creates a controller or view or model + index Adds an index to the configuration + + All commands can be run with -h for more information. + + DOC + end + def self.create - sub_cmd = ARGV.shift - case sub_cmd + case ARGV.shift when 'controller' - %Q{ -Usage: ml create controller[/function] [format] [options] + <<-DOC.strip_heredoc + Usage: ml create controller[/function] [format] [options] -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output - controller/function is the name of the controller and function. - The function is optional. If a function is omitted then main is assumed. + controller/function is the name of the controller and function. + The function is optional. If a function is omitted then main is assumed. - Format can be (none | html | xml | json). If no format is provided then - html is assumed. When "none" is provided no view is created. + Format can be (none | html | xml | json). If no format is provided then + html is assumed. When "none" is provided no view is created. - ex: ml create search/facet - This will create a controller named search.xqy containing - a function named search(). + ex: ml create search/facet + This will create a controller named search.xqy containing + a function named search(). - Html is assumed for the format thus a file named - views/search/facet.html.xqy will be created. -} + Html is assumed for the format thus a file named + views/search/facet.html.xqy will be created. + DOC when 'model' - %Q{ -Usage: ml create model model_name [file_name] [options] + <<-DOC.strip_heredoc + Usage: ml create model model_name [file_name] [options] -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output - model_name is the name of the model you wish to create. + model_name is the name of the model you wish to create. - file_name: You may optionally specify a file name. By default - the file will have the same name as the model. + file_name: You may optionally specify a file name. By default + the file will have the same name as the model. - ex: ml create model search - This will create a model named search in /app/models/search.xqy. - The namespace will be "http://marklogic.com/roxy/models/search". + ex: ml create model search + This will create a model named search in /app/models/search.xqy. + The namespace will be "http://marklogic.com/roxy/models/search". - ex: ml create model search search-lib.xqy - This will create a model named search.xqy in /app/models/search-lib.xqy. - The namespace will be "http://marklogic.com/roxy/models/search". -} + ex: ml create model search search-lib.xqy + This will create a model named search.xqy in /app/models/search-lib.xqy. + The namespace will be "http://marklogic.com/roxy/models/search". + DOC when 'test' - %Q{ -Usage: ml create test suite_name[/test] [options] + <<-DOC.strip_heredoc + Usage: ml create test suite_name[/test] [options] -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output - suite_name is the name of the suite you wish to create. + suite_name is the name of the suite you wish to create. - test: You may optionally specify the name of a test. If you omit test - then only the suite folder will be created + test: You may optionally specify the name of a test. If you omit test + then only the suite folder will be created - ex: ml create test users - This will create a test suite named users in /test/suites/users/. + ex: ml create test users + This will create a test suite named users in /test/suites/users/. - ex: ml create model users/login - This will create a test named login in /test/suites/users/login.xqy. -} + ex: ml create model users/login + This will create a test named login in /test/suites/users/login.xqy. + DOC when 'layout' - %Q{ -Usage: ml create layout layout_name [format] [options] + <<-DOC.strip_heredoc + Usage: ml create layout layout_name [format] [options] -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output - layout_name is the name of the layout you wish to create. + layout_name is the name of the layout you wish to create. - format can be (html | xml | json). If no format is provided then - html is assumed. + format can be (html | xml | json). If no format is provided then + html is assumed. - ex: ml create layout mobile - This will create a layout named mobile in /app/views/layouts/mobile.html.xqy. + ex: ml create layout mobile + This will create a layout named mobile in /app/views/layouts/mobile.html.xqy. - ex: ml create layout mobile json - This will create a layout named mobile in /app/views/layouts/mobile.json.xqy. -} + ex: ml create layout mobile json + This will create a layout named mobile in /app/views/layouts/mobile.json.xqy. + DOC else - %Q{ -Usage: ml create controller[/function] [format] [options] or - ml create model model_name [file_name] [options] or - ml create test suite_name [test] [options] or - ml create layout layout_name [format] [options] - -General options: - -v, [--verbose] # Verbose output - -For more details on each type use: - -ml create controller -h|--help -ml create model -h|--help -ml create test -h|--help -ml create layout -h|--help -} + <<-DOC.strip_heredoc + Usage: ml create controller[/function] [format] [options] or + ml create model model_name [file_name] [options] or + ml create test suite_name [test] [options] or + ml create layout layout_name [format] [options] + + General options: + -v, [--verbose] # Verbose output + + For more details on each type use: + + ml create controller -h|--help + ml create model -h|--help + ml create test -h|--help + ml create layout -h|--help + DOC end end def self.info - %Q{ -Usage: ml {env} info [options] + <<-DOC.strip_heredoc + Usage: ml {env} info [options] -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output -Displays the properties for the given environment} + Displays the properties for the given environment + DOC end def self.init - %Q{ -Usage: ml init [options] + <<-DOC.strip_heredoc + Usage: ml init [application-name] [options] -General options: - -v, [--verbose] # Verbose output + Optional Parameters: + application-name # The name of your application + General options: + --force # Force reset all configuration files + --force-properties # Force reset the properties file. (build.properties) + --force-config # Force reset the configuration file (ml-config.xml) + -v, [--verbose] # Verbose output -Initializes your application by creating the necessary config files} + + Initializes your application by creating the necessary config files. + DOC end def self.initcpf - %Q{ -Usage: ml initcpf [options] + <<-DOC.strip_heredoc + Usage: ml initcpf [options] -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output + --force # Force reset the config file -Initializes the necessary config files for cpf} + Initializes the necessary config files for cpf + DOC end def self.restart - %Q{ -Usage: ml {env} restart [group] [options] + <<-DOC.strip_heredoc + Usage: ml {env} restart [group] [options] -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output -Restart the MarkLogic process in the given environment on each host in the -specified group. If no group is specified, restart the MarkLogic process -on each host in the group to which the target host belongs.} + Restart the MarkLogic process in the given environment on each host in the + specified group. If no group is specified, restart the MarkLogic process + on each host in the group to which the target host belongs. + DOC end def self.bootstrap - %Q{ -Usage: ml {env} bootstrap [options] + <<-DOC.strip_heredoc + Usage: ml {env} bootstrap [options] -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output -Bootstraps your application to the MarkLogic server in the given -environment.} + Bootstraps your application to the MarkLogic server in the given + environment. + DOC end def self.wipe - %Q{ -Usage: ml {env} wipe [options] + <<-DOC.strip_heredoc + Usage: ml {env} wipe [options] -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output -Removes all traces of your application on the MarkLogic serverin the given -environment.} + Removes all traces of your application on the MarkLogic serverin the given + environment. + DOC end def self.deploy - %Q{ -Usage: ml {env} deploy WHAT [options] + <<-DOC.strip_heredoc + Usage: ml {env} deploy WHAT [options] -General options: - -v, [--verbose] # Verbose output - --batch=(yes|no) # enable or disable batch commit. By default - batch is disabled for the local environment - and enabled for all others. + General options: + -v, [--verbose] # Verbose output + --batch=(yes|no) # enable or disable batch commit. By default + batch is disabled for the local environment + and enabled for all others. -Please choose a WHAT below. + Please choose a WHAT below. - modules # deploys code to your modules db in the given environment - content # deploys content to your content db in the given environment - cpf # deploys your cpf config to the server in the given environment} + modules # deploys code to your modules db in the given environment + content # deploys content to your content db in the given environment + cpf # deploys your cpf config to the server in the given environment + DOC + end + + def self.load + <<-DOC.strip_heredoc + Usage: ml {env} load {/path/to/file-to-load} [options] + + General options: + -v, [--verbose] # Verbose output + --db=your-db-name # The name of the database to load into + defaults to your content database + --remove-prefix=/prefix/to/remove # The file path prefix to remove + DOC end def self.clean - %Q{ -Usage: ml {env} clean WHAT [options] + <<-DOC.strip_heredoc + Usage: ml {env} clean WHAT [options] -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output -Please choose a WHAT below. + Please choose a WHAT below. - modules # removes all data from the modules db in the given environment - content # removes all data from the content dv in the given environment - cpf # removes your cpf config from the server in the given environment} + modules # removes all data from the modules db in the given environment + content # removes all data from the content dv in the given environment + cpf # removes your cpf config from the server in the given environment + DOC end def self.test - %Q{ -Usage: ml {env} test [options] + <<-DOC.strip_heredoc + Usage: ml {env} test [options] -General options: - -v, [--verbose] # Verbose output - --skip-test-teardown # Skip teardown after each test - --skip-suite-teardown # Skip teardown after each suite + General options: + -v, [--verbose] # Verbose output + --skip-test-teardown # Skip teardown after each test + --skip-suite-teardown # Skip teardown after each suite -Runs your xquery unit tests on the given environment} + Runs your xquery unit tests on the given environment + DOC end def self.recordloader - %Q{ -Usage: ml {env} recordloader configfile [options] + <<-DOC.strip_heredoc + Usage: ml {env} recordloader configfile [options] -configfile must be a relative or absolute path to a Java properties file. -See http://marklogic.github.com/recordloader/ + configfile must be a relative or absolute path to a Java properties file. + See http://marklogic.github.com/recordloader/ -General options: - -v, [--verbose] # Verbose output + General options: + -v, [--verbose] # Verbose output -Runs recordloader with the given properties file. Properties files employ -variable substitution. + Runs recordloader with the given properties file. Properties files employ + variable substitution. -You may use variables like: + You may use variables like: -INPUT_PATH=${ml.data.dir}/} + INPUT_PATH=${ml.data.dir}/ + DOC end def self.xqsync - %Q{ -Usage: ml {env} xqsync configfile [options] + <<-DOC.strip_heredoc + Usage: ml {env} xqsync configfile [options] + + configfile must be a relative or absolute path to a Java properties file. + See http://marklogic.github.com/xqsync/ -configfile must be a relative or absolute path to a Java properties file. -See http://marklogic.github.com/xqsync/ + General options: + -v, [--verbose] # Verbose output -General options: - -v, [--verbose] # Verbose output + Runs xqsync with the given properties file. Properties files employ variable + substitution. -Runs xqsync with the given properties file. Properties files employ variable -substitution. + You may use variables like: -You may use variables like: + INPUT_PACKAGE=${ml.data.dir}/ + DOC + end + + def self.corb + <<-DOC.strip_heredoc + Usage: ml {env} corb [options] + + See: http://marklogic.github.com/corb/index.html + + Required options: + --modules=/path/to/modules.xqy # the xquery module to process the data -INPUT_PACKAGE=${ml.data.dir}/} + (Only one of the following is required) + --collection=collection-name # the name of a collection to process + --uris=/path/to/uris-module.xqy # path to a uris module + + Corb Options: + --threads=1 # the thread count to use + --root=/ # the root of the modules database + --install=false # whether or not to install (default: false) + + General options: + -v, [--verbose] # Verbose output + DOC end def self.plugin - %Q{ -Usage: ml {env} plugin [command] [package] [version] [options] + <<-DOC.strip_heredoc + Usage: ml {env} plugin [command] [package] [version] [options] -command: - (install|remove|list|refresh) + command: + (install|remove|list|refresh) -package: - Name of a depx package + package: + Name of a depx package -version: - Package Version + version: + Package Version -General options: - -v, [--verbose] # Verbose output} + General options: + -v, [--verbose] # Verbose output + DOC end def self.index - %Q{ -Usage: ml index - ml will ask questions to help you build an index - } + <<-DOC.strip_heredoc + Usage: ml index + ml will ask questions to help you build an index + DOC end - def self.doHelp(logger, command) - logger.formatter = proc { |severity, datetime, progname, msg| - "#{msg}\n" - } - - logger.info(eval("Help.#{command}")) + def self.doHelp(logger, command, error_message = nil) + logger.error "#{error_message}\n" if error_message + logger.info Help.send(command) end end \ No newline at end of file diff --git a/deploy/lib/MLClient.rb b/deploy/lib/MLClient.rb index 222230a1..89ef2fe4 100644 --- a/deploy/lib/MLClient.rb +++ b/deploy/lib/MLClient.rb @@ -45,7 +45,6 @@ def get_http def build_request_params(url, verb) uri = URI.parse url if (!@request[verb]) - logger.debug("creating new #{verb} request\n") @request[verb] = Net::HTTP.const_get(verb.capitalize).new(uri.request_uri) @request[verb].add_field 'Connection', 'keep-alive' @request[verb].add_field 'Keep-Alive', '30' diff --git a/deploy/lib/RoxyHttp.rb b/deploy/lib/RoxyHttp.rb index 8d6ca1bb..22a30e43 100644 --- a/deploy/lib/RoxyHttp.rb +++ b/deploy/lib/RoxyHttp.rb @@ -290,7 +290,6 @@ def start(request_params) @user_name = request_params[:user_name] @password = request_params[:password] - @logger.debug("Opening new #{@protocol.upcase} connection to #@server:#@port") @http = Net::HTTP.new(@server, @port) @http.open_timeout = @params[:http_connection_open_timeout] @http.read_timeout = @params[:http_connection_read_timeout] diff --git a/deploy/lib/framework.rb b/deploy/lib/framework.rb index bed65191..57320cb2 100644 --- a/deploy/lib/framework.rb +++ b/deploy/lib/framework.rb @@ -15,83 +15,77 @@ ############################################################################### module Roxy class Framework + + attr_reader :logger + def initialize(options) @logger = options[:logger] end def create - if (ARGV[0] == "model") then + if ARGV[0] == "model" burn = ARGV.shift #burn model arg str = ARGV.shift - if (str) then + if str model, function = str.split('/') filename = ARGV.shift || model - if (model != nil) then - create_model model, filename, function - end + create_model(model, filename, function) if model != nil else ARGV.unshift(burn) - Help.doHelp(@logger, "create") + Help.doHelp(logger, "create") end - elsif (ARGV[0] == "test") then + elsif ARGV[0] == "test" burn = ARGV.shift #burn test arg str = ARGV.shift if str suite, test = str.split('/') - if (suite != nil) then - create_suite suite, test - end + create_suite(suite, test) if suite != nil else ARGV.unshift(burn) - Help.doHelp(@logger, "create") + Help.doHelp(logger, "create") end - elsif (ARGV[0] == "layout") then + elsif ARGV[0] == "layout" burn = ARGV.shift #burn test arg layout = ARGV.shift format = ARGV.shift || "html" - if (layout != nil) then + if layout != nil create_layout(layout, format) else ARGV.unshift(burn) - Help.doHelp(@logger, "create") + Help.doHelp(logger, "create") end else force = find_arg(['-f']) != nil str = ARGV.shift - if (str) then + if str controller, view = str.split('/') view = view || "main" format = ARGV.shift || "html" - @logger.debug "controller: #{controller}" - @logger.debug "view: #{view}\n" - @logger.debug "format: #{format}\n" + logger.debug "controller: #{controller}" + logger.debug "view: #{view}\n" + logger.debug "format: #{format}\n" - if (controller != nil and view != nil) then - if (force == false) then - view_type = (format != nil and format != "none") ? ((format == "json") ? "a" : "an") + " #{format} view" : "no view" + if controller != nil && view != nil + if force == false + view_type = (format != nil && format != "none") ? ((format == "json") ? "a" : "an") + " #{format} view" : "no view" print "\nAbout to create a #{view}() function in the #{controller}.xqy controller with #{view_type}. Proceed?\n> " answer = gets() answer = answer.downcase.strip - if (answer != "y" and answer != "yes") then - return - end + return if answer != "y" && answer != "yes" end - create_controller controller, view - - if (format != nil and format != "none") then - create_view controller, view, format - end + create_controller(controller, view) + create_view(controller, view, format) unless format == nil || format == "none" end else - Help.doHelp(@logger, "create") + Help.doHelp(logger, "create") end end end @@ -99,16 +93,16 @@ def create def create_model(model, filename, function) target_file = File.expand_path("../../../src/app/models/#{filename}.xqy", __FILE__) model_file = nil - if File.exists? target_file then - if (function != nil) then - model_file = File.read(target_file) + if File.exists? target_file + if function != nil + model_file = File.read target_file - if (model_file.index("m:#{function}()") != nil) then - @logger.warn "Function #{model}:#{function}() already exists. Skipping..." + if model_file.index("m:#{function}()") != nil + logger.warn "Function #{model}:#{function}() already exists. Skipping..." return end else - @logger.warn "Model #{model} already exists. Skipping..." + logger.warn "Model #{model} already exists. Skipping..." return end else @@ -116,7 +110,7 @@ def create_model(model, filename, function) model_file.gsub!("#model-name", model) end - if (function != nil) then + if function != nil model_file << File.read(File.expand_path('../templates/model-function.xqy', __FILE__)) model_file.gsub!("#function-name", function) end @@ -125,17 +119,17 @@ def create_model(model, filename, function) def create_suite(suite, test) suite_dir = File.expand_path("../../../src/test/suites/#{suite}/", __FILE__) - Dir.mkdir(suite_dir) unless File.directory?(suite_dir) + Dir.mkdir(suite_dir) unless File.directory? suite_dir - if (test) + if test target_file = "#{suite_dir}/#{test}.xqy" test_file = nil - if File.exists? target_file then - @logger.warn "Test #{test} already exists. Skipping..." + if File.exists? target_file + logger.warn "Test #{test} already exists. Skipping..." return else - test_file = open(File.expand_path('../templates/test.xqy', __FILE__)).readlines.join + test_file = File.read(File.expand_path('../templates/test.xqy', __FILE__)) end File.open(target_file, 'a') {|f| f.write(test_file) } @@ -144,13 +138,13 @@ def create_suite(suite, test) def create_layout(layout, format) layout_dir = File.expand_path("../../../src/app/views/layouts/", __FILE__) - Dir.mkdir(layout_dir) unless File.directory?(layout_dir) + Dir.mkdir(layout_dir) unless File.directory? layout_dir target_file = "#{layout_dir}/#{layout}.#{format}.xqy" layout_file = nil - if File.exists? target_file then - @logger.warn "Layout #{layout}.#{format} already exists. Skipping..." + if File.exists? target_file + logger.warn "Layout #{layout}.#{format} already exists. Skipping..." return else layout_file = File.expand_path("../templates/layout.#{format}.xqy", __FILE__) @@ -164,16 +158,16 @@ def create_layout(layout, format) def create_controller(controller, view) target_file = File.expand_path("../../../src/app/controllers/#{controller}.xqy", __FILE__) controller_file = nil - if File.exists? target_file then - existing = open(target_file).readlines.join + if File.exists? target_file + existing = File.read(target_file) - if (existing.index("c:#{view}()") != nil) then - @logger.warn "function #{controller}:#{view}() already exists. Skipping..." + if existing.index("c:#{view}()") != nil + logger.warn "function #{controller}:#{view}() already exists. Skipping..." return end - controller_file = open(File.expand_path('../templates/controller-function.xqy', __FILE__)).readlines.join + controller_file = File.read File.expand_path('../templates/controller-function.xqy', __FILE__) else - controller_file = open(File.expand_path('../templates/controller.xqy', __FILE__)).readlines.join + controller_file = File.read File.expand_path('../templates/controller.xqy', __FILE__) end controller_file.gsub!("#controller-name", controller) @@ -183,23 +177,21 @@ def create_controller(controller, view) def create_view(controller, view, format) dir = File.expand_path("../../../src/app/views/#{controller}/", __FILE__) - if File.directory?(dir) == false - Dir.mkdir(dir) - end + Dir.mkdir(dir) unless File.directory? dir out_file = "#{dir}/#{view}.#{format}.xqy" template_file = File.expand_path("../templates/view.#{format}.xqy", __FILE__) template_file = File.expand_path("../templates/view.xqy", __FILE__) unless File.exists?(template_file) - if File.exists?(out_file) == false then - view_template = open(template_file).readlines.join + if File.exists?(out_file) == false + view_template = File.read template_file view_template.gsub!("#location", out_file) view_template.gsub!("#controller", controller) view_template.gsub!("#view", view) File.open(out_file, 'w') {|f| f.write(view_template) } else - @logger.warn "View #{out_file} already exists. Skipping..." + logger.warn "View #{out_file} already exists. Skipping..." end end end diff --git a/deploy/lib/ml.rb b/deploy/lib/ml.rb index 411789fe..6d4ac818 100755 --- a/deploy/lib/ml.rb +++ b/deploy/lib/ml.rb @@ -19,32 +19,6 @@ require 'util' require 'app_specific' -def usage -puts <<-EOT -Usage: ml COMMAND [ARGS] - -Deployment Commands: - init Creates configuration files for you to customize - initcpf Creates cpf configuration files for you to customize - info Return settings for a given environment - bootstrap Configures your application on the MarkLogic server - wipe Remove your configuration from the MarkLogic server - restart Restart your MarkLogic server - deploy Loads modules, data, cpf configuration into the server - clean Removes all files from the cpf, modules, or content databases - info Prints the configuration information - test Runs xquery unit tests - recordloader Runs RecordLoader - xqsync Runs XQSync - -Roxy MVC Commands: - create Creates a controller or view or model - index Adds an index to the configuration - -All commands can be run with -h for more information. -EOT -end - def need_help? find_arg(['-h', '--help']) != nil end @@ -65,123 +39,97 @@ def need_help? @logger = Logger.new(STDOUT) @logger.level = find_arg(['-v', '--verbose']) ? Logger::DEBUG : Logger::INFO @logger.formatter = proc { |severity, datetime, progname, msg| - "#{severity}: #{msg}\n" + sev = "#{severity}: " if severity == "ERROR" + "#{sev}#{msg}\n" } -begin -while ARGV.length > 0 - command = ARGV.shift +if RUBY_VERSION < "1.8.7" + @logger.warn <<-MSG - if ["-h", "--help"].include?(command) - usage - break - # - # Roxy framework is a convenience utility for create MVC code - # - elsif (command == "create") - if need_help? - Help.doHelp(@logger, command) - break - else - f = Roxy::Framework.new(:logger => @logger) - f.create# ARGV.join - end - # - # put things in ServerConfig class methods that don't depend on environment or server info - # - elsif (ServerConfig.respond_to?(command.to_sym) || ServerConfig.respond_to?(command)) - if need_help? - Help.doHelp(@logger, command) - break - else - ServerConfig.set_logger @logger - eval "ServerConfig.#{command}" - end - - # - # ServerConfig methods require environment to be set in order to talk to a ML server - # - else - - ARGV.unshift(command) - - @properties = ServerConfig.properties - if (@properties["environment"] == nil) - raise ExitException.new("Missing environment for #{command}") - end + WARNING!!! + You are using a very old version of Ruby: #{RUBY_VERSION} + Roxy works best with Ruby 1.8.7 or greater. + Proceed with caution. + MSG +end +begin + while ARGV.length > 0 command = ARGV.shift - if need_help? - Help.doHelp(@logger, command) + # + # Roxy framework is a convenience utility for create MVC code + # + if command == "create" + if need_help? + Help.doHelp(@logger, command) break - elsif (ServerConfig.instance_methods.include?(command.to_sym) || ServerConfig.instance_methods.include?(command)) - - - if (@properties["ml.config.file"] == nil) - raise ExitException.new "Missing ml-config.xml file. Check config.file property" + else + f = Roxy::Framework.new :logger => @logger + f.create end + # + # put things in ServerConfig class methods that don't depend on environment or server info + # + elsif ServerConfig.respond_to?(command.to_sym) || ServerConfig.respond_to?(command) + if need_help? + Help.doHelp(@logger, command) + break + else + ServerConfig.logger = @logger + ServerConfig.send command + end + # + # ServerConfig methods require environment to be set in order to talk to a ML server + # + else + # unshift to get the environment in ServerConfig.properties + ARGV.unshift command + @properties = ServerConfig.properties + command = ARGV.shift - @s = ServerConfig.new({ - :config_file => File.expand_path(@properties["ml.config.file"], __FILE__), - :properties => @properties, - :logger => @logger - }) - - case command - when 'load' - dir = ARGV[0] - db = ARGV[1] - remove_prefix = "" - if (ARGV.include?('-r')) - index = ARGV.index('-r') + 1 - if (ARGV.size > index) - remove_prefix = ARGV[index] - else - @logger.error("invalid option") - end - elsif (ARGV.include?('--remove-prefix')) - # index = ARGV.index('-v') || ARGV.index('--verbose') - # ARGV.slice!(index) - end - - if (dir && db) - @s.load_data dir, remove_prefix, db - else - puts "Error: Destination directory and Database are required" - end - else - @s.send(command) - end + if need_help? && Help.respond_to?(command) + Help.doHelp(@logger, command) + break + elsif ServerConfig.instance_methods.include?(command) + raise HelpException.new(command, "Missing environment for #{command}") if @properties["environment"].nil? + raise ExitException.new("Missing ml-config.xml file. Check config.file property") if @properties["ml.config.file"].nil? + + @s = ServerConfig.new( + :config_file => File.expand_path(@properties["ml.config.file"], __FILE__), + :properties => @properties, + :logger => @logger + ).send(command) else - puts "Error: Command not recognized" unless ['-h', '--help'].include?(command) - usage + Help.doHelp(@logger, :usage) break end end end - rescue Net::HTTPServerException => e - case e.response - when Net::HTTPUnauthorized then - @logger.error("Invalid login credentials for #{@properties["environment"]} environment!!") - else - @logger.error(e) - @logger.error(e.response.body) - end - rescue Net::HTTPFatalError => e - @logger.error(e) - @logger.error(e.response.body) +rescue Net::HTTPServerException => e + case e.response + when Net::HTTPUnauthorized then + @logger.error "Invalid login credentials for #{@properties["environment"]} environment!!" + else + @logger.error e + @logger.error e.response.body + end +rescue Net::HTTPFatalError => e + @logger.error e + @logger.error e.response.body rescue DanglingVarsException => e @logger.error "WARNING: The following configuration variables could not be validated:" e.vars.each do |k,v| @logger.error "#{k}=#{v}" end +rescue HelpException => e + Help.doHelp(@logger, e.command, e.message) rescue ExitException => e - @logger.error(e) - rescue Exception => e - @logger.error(e) - @logger.error(e.backtrace) - end + @logger.error e +rescue Exception => e + @logger.error e + @logger.error e.backtrace +end if @profile then result = RubyProf.stop @@ -189,4 +137,4 @@ def need_help? # Print a flat profile to text printer = RubyProf::FlatPrinter.new(result) printer.print(STDOUT) -end +end \ No newline at end of file diff --git a/deploy/lib/server_config.rb b/deploy/lib/server_config.rb index 81488818..9ea7ac4e 100644 --- a/deploy/lib/server_config.rb +++ b/deploy/lib/server_config.rb @@ -21,7 +21,14 @@ require 'xcc' require 'MLClient' -class ExitException < Exception +class ExitException < Exception; end + +class HelpException < Exception + attr_reader :command, :message + def initialize(command, message = nil) + @command = command + @message = message + end end class DanglingVarsException < Exception @@ -43,38 +50,30 @@ def initialize(options) @environment = @properties["environment"] @config_file = @properties["ml.config.file"] - if (!@properties["ml.server"]) then - @properties["ml.server"] = @properties["ml.#{@environment}-server"] - end + @properties["ml.server"] = @properties["ml.#{@environment}-server"] unless @properties["ml.server"] + @hostname = @properties["ml.server"] @bootstrap_port_four = @properties["ml.bootstrap-port-four"] @bootstrap_port_five = @properties["ml.bootstrap-port-five"] - super({ + super( :user_name => @properties["ml.user"], :password => @properties["ml.password"], :logger => options[:logger] - }) + ) @server_version = @properties["ml.server-version"].to_i - if (@properties["ml.bootstrap-port"]) + if @properties["ml.bootstrap-port"] @bootstrap_port = @properties["ml.bootstrap-port"] else - if (@server_version == 4) then + if @server_version == 4 @bootstrap_port = @bootstrap_port_four else @bootstrap_port = @bootstrap_port_five @properties["ml.bootstrap-port"] = @bootstrap_port end end - - logger.debug "config: #{@config_file}" - logger.debug "pwd: #{ServerConfig.pwd}" - logger.debug "user: #{@ml_username}" - logger.debug "password: #{@ml_password}" - logger.debug "hostname: #{@hostname}" - logger.debug "port: #{@bootstrap_port}" end def self.pwd @@ -93,47 +92,57 @@ def info end def self.init - # allow the caller to replace roxy with the new app name sample_config = File.expand_path("../../sample/ml-config.sample.xml", __FILE__) sample_properties = File.expand_path("../../sample/build.sample.properties", __FILE__) build_properties = File.expand_path("../../build.properties", __FILE__) - force = find_arg(['--force']) != nil ? true : false - force_props = find_arg(['--force-properties']) != nil ? true : false - force_config = find_arg(['--force-config']) != nil ? true : false - if (!force and !force_props and File.exists?(build_properties)) then - logger.error "build.properties file found." - logger.error " Use --force to reset all configuration files." - logger.error " Use --force-properties to reset just the properties file.\n" + + force = find_arg(['--force']).present? + force_props = find_arg(['--force-properties']).present? + force_config = find_arg(['--force-config']).present? + + error_msg = [] + if !force && !force_props && File.exists?(build_properties) + error_msg << "build.properties has already been created." else #create clean properties file FileUtils.cp sample_properties, build_properties + properties_file = File.read(build_properties) + + # replace the appname if one is provided name = ARGV.shift - if (name) - properties_file = open(build_properties).read - properties_file.gsub!(/app-name=roxy/, "app-name=#{name}") - open(build_properties, 'w') {|f| f.write(properties_file) } + properties_file.gsub!(/app-name=roxy/, "app-name=#{name}") if name + + # replace the text =random with a random string + o = (33..126).to_a + properties_file.gsub!(/=random/) do |match| + random = (0...20).map{ o[rand(o.length)].chr }.join + "=#{random}" end + + # save the replacements + open(build_properties, 'w') {|f| f.write(properties_file) } end - properties = ServerConfig.properties - target_config = File.expand_path(properties["ml.config.file"], __FILE__) - if (!force and !force_config and File.exists?(target_config)) then - logger.error "ml-config.xml file found." - logger.error " Use --force to reset all configuration files." - logger.error " Use --force-config to reset just the configuration file.\n" + target_config = File.expand_path(ServerConfig.properties["ml.config.file"], __FILE__) + + if !force && !force_config && File.exists?(target_config) + error_msg << "ml-config.xml has already been created." else #create clean marklogic configuration file FileUtils.cp sample_config, target_config end + + raise HelpException.new("init", error_msg.join("\n")) if error_msg.length > 0 end def self.initcpf sample_config = File.expand_path("../../sample/pipeline-config.sample.xml", __FILE__) target_config = File.expand_path("../../pipeline-config.xml", __FILE__) - if (File.exists?(target_config)) then - logger.error "initcpf has already been run. Use --force to rerun it.\n" + force = find_arg(['--force']).present? + if !force && File.exists?(target_config) + raise HelpException.new("initcpf", "cpf configuration has already been created.") else FileUtils.cp sample_config, target_config end @@ -172,10 +181,7 @@ def self.request_type def self.request_collation puts "What is the collation URI (leave blank for the root collation)?" collation = gets.chomp - if collation == "" - collation = "http://marklogic.com/collation/" - end - collation + collation = "http://marklogic.com/collation/" if collation.blank? end def self.request_range_value_positions @@ -192,7 +198,7 @@ def self.request_range_value_positions def self.inject_index(key, index) properties = ServerConfig.properties config_path = File.expand_path(properties["ml.config.file"], __FILE__) - existing = File.read(config_path) { |file| file.readlines.join } + existing = File.read(config_path) existing = existing.gsub(key) { |match| "#{match}\n#{index}" } File.open(config_path, "w") { |file| file.write(existing) } end @@ -207,9 +213,7 @@ def self.build_attribute_element_index uri = gets.chomp puts "What is the attribute's localname?" localname = gets.chomp - if scalar_type == "string" # string - collation = request_collation - end + collation = request_collation if scalar_type == "string" positions = request_range_value_positions index = " #{scalar_type} @@ -236,9 +240,7 @@ def self.build_element_index uri = gets.chomp puts "What is the element's localname?" localname = gets.chomp - if scalar_type == "string" # string - collation = request_collation - end + collation = request_collation if scalar_type == "string" # string positions = request_range_value_positions index = " #{scalar_type} @@ -264,21 +266,19 @@ def execute_query(query, properties = {}) r = execute_query_5 query, properties end - if (r.code.to_i != 200) - raise ExitException.new(r.body) - end + raise ExitException.new(r.body) unless r.code.to_i == 200 return r end def restart group = ARGV.shift - if (group) - logger.info("Restarting MarkLogic Server group #{group} on #{@hostname}") + if group + logger.info "Restarting MarkLogic Server group #{group} on #{@hostname}" else - logger.info("Restarting MarkLogic Server on #{@hostname}") + logger.info "Restarting MarkLogic Server on #{@hostname}" end - setup = open(File.expand_path('../xquery/setup.xqy', __FILE__)).readlines.join + setup = File.read File.expand_path('../xquery/setup.xqy', __FILE__) r = execute_query %Q{#{setup} setup:do-restart("#{group}")} end @@ -291,7 +291,7 @@ def self.plugin package_version = ARGV.shift if ARGV.length runme = %Q{cd #{src_dir} && } - if (is_windows?) then + if is_windows? runme << File.expand_path("../depx-0.1/depx.bat", __FILE__) else runme << File.expand_path("../depx-0.1/depx", __FILE__) @@ -301,8 +301,7 @@ def self.plugin runme << " #{package_version} " if package_version logger.debug runme - output = `#{runme}` - logger.info(output) + logger.info `#{runme}` end def config @@ -310,65 +309,63 @@ def config end def bootstrap - if @hostname && @hostname != "" - logger.info("Bootstrapping your project into MarkLogic on #{@hostname}...") - setup = open(File.expand_path('../xquery/setup.xqy', __FILE__)).readlines.join - r = execute_query %Q{#{setup} setup:do-setup(#{get_config})} + raise ExitException.new("Bootstrap requires the target environment's hostname to be defined") unless @hostname.present? - logger.debug r.body + logger.info "Bootstrapping your project into MarkLogic on #{@hostname}..." + setup = File.read(File.expand_path('../xquery/setup.xqy', __FILE__)) + r = execute_query %Q{#{setup} setup:do-setup(#{get_config})} - if (r.body.match(" e @@ -377,54 +374,44 @@ def validate_install result = false end result - - # logger.debug r.body - - # if (r.body.match(" remove_prefix, :add_prefix => add_prefix, :db => db, :quiet => quiet + logger.info "\nLoaded #{count} #{pluralize(count, "document", "documents")} from #{dir} to #{xcc.hostname}:#{xcc.port}/#{db}\n" + end + def load_data(dir, options = {}) - batch_override = nil - if (ARGV[0] && ARGV[0].match("--batch=(yes|no)")) - batch_override = ARGV.shift.split("=")[1] == "yes" - end - batch = (((@environment != "local") && (batch_override != false)) || (batch_override == true)) + batch_override = find_arg(['--batch']) + batch = @environment != "local" && batch_override.blank? || batch_override.to_b options[:batch_commit] = batch - options[:permissions] = - [ - { - :capability => Roxy::ContentCapability::EXECUTE, - :role => @properties['ml.app-role'] - }, - { - :capability => Roxy::ContentCapability::READ, - :role => @properties['ml.app-role'] - } - ] unless options[:permissions] + options[:permissions] = permissions(@properties['ml.app-role'], Roxy::ContentCapability::ER) unless options[:permissions] xcc.load_files(File.expand_path(dir), options) end @@ -438,21 +425,21 @@ def load_data(dir, options = {}) # def clean what = ARGV.shift - if (what) - case what - when 'content' - clean_content - when 'modules' - clean_modules - when 'triggers' - clean_triggers - when 'schemas' - clean_schemas - when 'cpf' - clean_cpf - end - else - puts Help.clean + raise HelpException.new("clean", "Missing WHAT") unless what + + case what + when 'content' + clean_content + when 'modules' + clean_modules + when 'triggers' + clean_triggers + when 'schemas' + clean_schemas + when 'cpf' + clean_cpf + else + raise HelpException.new("clean", "Invalid WHAT") end end @@ -460,15 +447,15 @@ def clean # Invokes unit tests for the project # def test - if (@environment == "prod") then + if @environment == "prod" logger.error "There is no Test database on the Production server" else - if (find_arg(['--skip-suite-teardown']) != nil) + if find_arg(['--skip-suite-teardown']).present? suiteTearDown = "&runsuiteteardown=false" else suiteTearDown = "&runsuiteteardown=true" end - if (find_arg(['--skip-test-teardown']) != nil) + if find_arg(['--skip-test-teardown']).present? testTearDown = "&runteardown=false" else testTearDown = "&runteardown=true" @@ -476,9 +463,7 @@ def test r = go %Q{http://#{@hostname}:#{@properties["ml.test-port"]}/test/list}, "get" suites = [] r.body.split(">").each do |line| - if (line.match("suite path")) then - suites << line.gsub(/.*suite path="([^"]+)".*/, '\1').strip - end + suites << line.gsub(/.*suite path="([^"]+)".*/, '\1').strip if line.match("suite path") end suites.each do |suite| @@ -505,17 +490,15 @@ def is_backup_complete(job) r = execute_query %Q{xdmp:database-backup-status(#{job})} statuses = [] r.body.split("\n").each do |line| - if (line.match("job:status")) then - statuses << line.gsub(/.*([^<]+)<\/job:status>/, '\1').strip - end + statuses << line.gsub(/.*([^<]+)<\/job:status>/, '\1').strip if line.match("job:status") end completed_count = 0 failed_count = 0 statuses.each do |status| - if (status == "completed") then + if status == "completed" completed_count = completed_count + 1 - elsif (status == "failed") then + elsif status == "failed" failed_count = failed_count + 1 end end @@ -526,12 +509,14 @@ def is_backup_complete(job) end def recordloader - properties_file = File.expand_path("../../#{ARGV.shift}", __FILE__) + filename = ARGV.shift + raise HelpException.new("recordloader", "configfile is required!") unless filename + properties_file = File.expand_path("../../#{filename}", __FILE__) properties = ServerConfig.load_properties(properties_file, "") properties = ServerConfig.substitute_properties(properties, @properties, "") properties.each do |k, v| - logger.info("#{k}=#{v}") + logger.debug "#{k}=#{v}" end prop_string = "" @@ -545,12 +530,14 @@ def recordloader end def xqsync - properties_file = File.expand_path("../../#{ARGV.shift}", __FILE__) + filename = ARGV.shift + raise HelpException.new("xqsync", "configfile is required!") unless filename + properties_file = File.expand_path("../../#{filename}", __FILE__) properties = ServerConfig.load_properties(properties_file, "") properties = ServerConfig.substitute_properties(properties, @properties, "") properties.each do |k, v| - logger.info("#{k}=#{v}") + logger.debug "#{k}=#{v}" end prop_string = "" properties.each do |k,v| @@ -562,180 +549,145 @@ def xqsync `#{runme}` end -private - def deploy_modules - ignore_us = [] - ignore_us = ["^#{@properties['ml.xquery-test.dir']}.*$"] if @properties['ml.xquery-test.dir'] - app_config_file = "#{@properties['ml.xquery.dir']}/app/config/config.xqy" - ignore_us << "^#{app_config_file}$" - load_data @properties["ml.xquery.dir"], { - :add_prefix => "/", - :remove_prefix => @properties["ml.xquery.dir"], - :db => @properties['ml.modules-db'], - :ignore_list => ignore_us - } + def corb + connection_string = %Q{xcc://#{@properties['ml.app-name']}-user:#{@properties['ml.appuser-password']}@#{@properties['ml.server']}:#{@properties['ml.xcc-port']}/#{@properties['ml.content-db']}} + collection_name = find_arg(['--collection']) || '""' + xquery_module = find_arg(['--modules']) + uris_module = find_arg(['--uris']) || '""' - if (File.exist?(app_config_file)) - buffer = open(app_config_file).readlines.join - @properties.each do |k, v| - buffer.gsub!("@#{k}", v) - end - xcc.load_buffer("/config.xqy", buffer,{ - :db => @properties['ml.modules-db'], - :add_prefix => File.join(@properties["ml.modules-root"], "app/config"), - :permissions => [ - { - :capability => Roxy::ContentCapability::EXECUTE, - :role => @properties['ml.app-role'] - }, - { - :capability => Roxy::ContentCapability::READ, - :role => @properties['ml.app-role'] - } - ] - }) + raise HelpException.new("corb", "modules is required") if xquery_module.blank? + raise HelpException.new("corb", "uris or collection is required ") if uris_module == '""' && collection_name == '""' + + xquery_module = xquery_module.reverse.chomp("/").reverse + uris_module = uris_module.reverse.chomp("/").reverse + thread_count = find_arg(['--threads']) || "1" + thread_count = thread_count.to_i + module_root = find_arg(['--root']) || '"/"' + modules_database = @properties['ml.modules-db'] + install = find_arg(['install']) == "true" + + matches = Dir.glob(File.expand_path("../java/*xcc*.jar", __FILE__)) + raise "Missing XCC Jar." if matches.length == 0 + + xcc_file = matches[0] + runme = %Q{java -cp #{File.expand_path("../java/corb.jar", __FILE__)}#{path_separator}#{xcc_file} com.marklogic.developer.corb.Manager #{connection_string} #{collection_name} #{xquery_module} #{thread_count} #{uris_module} #{module_root} #{modules_database} #{install}} + logger.info runme + `#{runme}` + end + +private + + def permissions(role, capabilities) + capabilities.map do |c| + { + :capability => c, + :role => role + } end - # only deploy test code if test db is enabled. - # don't deploy tests to prod - if (@properties['ml.test-content-db'] && @properties['ml.test-content-db'] != "" && - @properties['ml.test-port'] && @properties['ml.test-port'] != "" && - @environment != "prod") - - test_config_file = "#{@properties['ml.xquery-test.dir']}/test-config.xqy" - - # if the test-modules-db is different from the app modules db, also load the - # app modules into it - if (@properties['ml.test-modules-db'] && @properties['ml.test-modules-db'] != "" && - @properties['ml.test-modules-db'] != @properties['ml.modules-db']) - load_data @properties["ml.xquery-test.dir"], { - :add_prefix => File.join(@properties["ml.modules-root"], "test"), - :remove_prefix => @properties["ml.xquery-test.dir"], - :db => @properties['ml.test-modules-db'], - :ignore_list => ["^#{test_config_file}$"] - } - - if (File.exist?(test_config_file)) - buffer = open(test_config_file).readlines.join - @properties.each do |k, v| - buffer.gsub!("@#{k}", v) - end + end - xcc.load_buffer("/test-config.xqy", buffer,{ - :db => @properties['ml.test-modules-db'], - :add_prefix => File.join(@properties["ml.modules-root"], "test"), - :permissions => [ - { - :capability => Roxy::ContentCapability::EXECUTE, - :role => @properties['ml.app-role'] - } - ] - }) - end + def deploy_tests?(target_db) + @properties['ml.test-content-db'].present? && + @properties['ml.test-port'].present? && + @environment != "prod" && + @properties['ml.test-modules-db'] == target_db + end - load_data @properties["ml.xquery.dir"], { - :add_prefix => "/", - :remove_prefix => @properties["ml.xquery.dir"], - :db => @properties['ml.test-modules-db'], - :ignore_list => ignore_us - } - - if (File.exist?(app_config_file)) - buffer = open(app_config_file).readlines.join - @properties.each do |k, v| - buffer.gsub!("@#{k}", v) - end + def modules_databases + dbs = [@properties['ml.modules-db']] + dbs << @properties['ml.test-modules-db'] if @properties['ml.test-modules-db'].present? && + @properties['ml.test-modules-db'] != @properties['ml.modules-db'] + dbs + end - xcc.load_buffer("/config.xqy", buffer,{ - :db => @properties['ml.test-modules-db'], - :add_prefix => File.join(@properties["ml.modules-root"], "app/config"), - :permissions => [ - { - :capability => Roxy::ContentCapability::EXECUTE, - :role => @properties['ml.app-role'] - }, - { - :capability => Roxy::ContentCapability::READ, - :role => @properties['ml.app-role'] - } - ] - }) + def deploy_modules + test_dir = @properties['ml.xquery-test.dir'] + xquery_dir = @properties['ml.xquery.dir'] + # modules_db = @properties['ml.modules-db'] + app_config_file = File.join xquery_dir, "/app/config/config.xqy" + test_config_file = File.join test_dir, "/test-config.xqy" + + modules_databases.each do |dest_db| + ignore_us = [] + ignore_us << "^#{test_dir}.*$" unless test_dir.blank? || deploy_tests?(dest_db) + ignore_us << "^#{app_config_file}$" + ignore_us << "^#{test_config_file}$" + + total_count = load_data xquery_dir, + :add_prefix => "/", + :remove_prefix => xquery_dir, + :db => dest_db, + :ignore_list => ignore_us + + if File.exist? app_config_file + buffer = File.read app_config_file + @properties.each do |k, v| + buffer.gsub!("@#{k}", v) end - else - load_data @properties["ml.xquery-test.dir"], { - :add_prefix => File.join(@properties["ml.modules-root"], "test"), - :remove_prefix => @properties["ml.xquery-test.dir"], - :db => @properties['ml.modules-db'], - :ignore_list => ["^#{test_config_file}$"] - } - - if (File.exist?(test_config_file)) - buffer = open(test_config_file).readlines.join - @properties.each do |k, v| - buffer.gsub!("@#{k}", v) - end - xcc.load_buffer("/test-config.xqy", buffer,{ - :db => @properties['ml.modules-db'], - :add_prefix => File.join(@properties["ml.modules-root"], "test"), - :permissions => [ - { - :capability => Roxy::ContentCapability::EXECUTE, - :role => @properties['ml.app-role'] - } - ] - }) + total_count += xcc.load_buffer "/config.xqy", + buffer, + :db => dest_db, + :add_prefix => File.join(@properties["ml.modules-root"], "app/config"), + :permissions => permissions(@properties['ml.app-role'], Roxy::ContentCapability::ER) + end + + if deploy_tests?(dest_db) && File.exist?(test_config_file) + buffer = File.read test_config_file + @properties.each do |k, v| + buffer.gsub!("@#{k}", v) end + + total_count += xcc.load_buffer "/test-config.xqy", + buffer, + :db => dest_db, + :add_prefix => File.join(@properties["ml.modules-root"], "test"), + :permissions => permissions(@properties['ml.app-role'], Roxy::ContentCapability::EXECUTE) end + + logger.info "\nLoaded #{total_count} #{pluralize(total_count, "document", "documents")} from #{xquery_dir} to #{xcc.hostname}:#{xcc.port}/#{dest_db}\n" end end def clean_modules - logger.info("Cleaning #{@properties['ml.modules-db']} on #{@hostname}") + logger.info "Cleaning #{@properties['ml.modules-db']} on #{@hostname}" execute_query %Q{xdmp:forest-clear(xdmp:forest("#{@properties['ml.modules-db']}"))} - if (@properties['ml.test-modules-db'] && @properties['ml.test-modules-db'] != @properties['ml.modules-db']) - logger.info("Cleaning #{@properties['ml.test-modules-db']} on #{@hostname}") + + if @properties['ml.test-modules-db'].present? && @properties['ml.test-modules-db'] != @properties['ml.modules-db'] + logger.info "Cleaning #{@properties['ml.test-modules-db']} on #{@hostname}" execute_query %Q{xdmp:forest-clear(xdmp:forest("#{@properties['ml.test-modules-db']}"))} end end def clean_schemas - if (@properties['ml.schemas-db']) - logger.info("Cleaning #{@properties['ml.schemas-db']} on #{@hostname}") + if @properties['ml.schemas-db'] + logger.info "Cleaning #{@properties['ml.schemas-db']} on #{@hostname}" execute_query %Q{xdmp:forest-clear(xdmp:forest("#{@properties['ml.schemas-db']}"))} else - logger.error("No schemas db is configured") + logger.error "No schemas db is configured" end end def clean_triggers - if (@properties['ml.triggers-db']) - logger.info("Cleaning #{@properties['ml.triggers-db']} on #{@hostname}") + if @properties['ml.triggers-db'] + logger.info "Cleaning #{@properties['ml.triggers-db']} on #{@hostname}" execute_query %Q{xdmp:forest-clear(xdmp:forest("#{@properties['ml.triggers-db']}"))} else - logger.error("No triggers db is configured") + logger.error "No triggers db is configured" end end def deploy_content - load_data @properties["ml.data.dir"], { - :remove_prefix => @properties["ml.data.dir"], - :db => @properties['ml.content-db'], - :permissions => [ - { - :capability => Roxy::ContentCapability::READ, - :role => @properties['ml.app-role'] - }, - { - :capability => Roxy::ContentCapability::UPDATE, - :role => @properties['ml.app-role'] - } - ] - } + count = load_data @properties["ml.data.dir"], + :remove_prefix => @properties["ml.data.dir"], + :db => @properties['ml.content-db'], + :permissions => permissions(@properties['ml.app-role'], Roxy::ContentCapability::RU) + logger.info "\nLoaded #{count} #{pluralize(count, "document", "documents")} from #{@properties["ml.data.dir"]} to #{xcc.hostname}:#{xcc.port}/#{@properties['ml.content-db']}\n" end def clean_content - logger.info("Cleaning #{@properties['ml.content-db']} on #{@hostname}") + logger.info "Cleaning #{@properties['ml.content-db']} on #{@hostname}" execute_query %Q{ for $id in xdmp:database-forests(xdmp:database("#{@properties['ml.content-db']}")) return @@ -744,97 +696,92 @@ def clean_content end def deploy_cpf - if (!@properties["ml.triggers-db"] || @properties["ml.data.dir"] == "") - logger.error("To use CPF, you must define the triggers-db property in your build.properties file") - elsif (!File.exist?(File.expand_path("../../pipeline-config.xml", __FILE__))) - logger.error(" -Before you can deploy CPF, you must define a configuration. Steps: -1. Run 'ml initcpf' -2. Edit deploy/pipeline-config.xml to set up your domain and pipelines -3. Run 'ml deploy cpf')") + if @properties["ml.triggers-db"].blank? || @properties["ml.data.dir"].blank? + logger.error "To use CPF, you must define the triggers-db property in your build.properties file" + elsif !File.exist?(File.expand_path("../../pipeline-config.xml", __FILE__)) + logger.error <<-ERR.strip_heredoc + Before you can deploy CPF, you must define a configuration. Steps: + 1. Run 'ml initcpf' + 2. Edit deploy/pipeline-config.xml to set up your domain and pipelines + 3. Run 'ml deploy cpf') + ERR else - cpf_config = open(File.expand_path("../../pipeline-config.xml", __FILE__)).readlines.join + cpf_config = File.read File.expand_path("../../pipeline-config.xml", __FILE__) @properties.each do |k, v| cpf_config.gsub!("@#{k}", v) end - cpf_code = open(File.expand_path('../xquery/cpf.xqy', __FILE__)).readlines.join - r = execute_query %Q{#{cpf_code} cpf:load-from-config(#{cpf_config})}, { :db_name => @properties["ml.content-db"] } + cpf_code = File.read File.expand_path('../xquery/cpf.xqy', __FILE__) + r = execute_query %Q{#{cpf_code} cpf:load-from-config(#{cpf_config})}, :db_name => @properties["ml.content-db"] end end def clean_cpf - cpf_code = open(File.expand_path('../xquery/cpf.xqy', __FILE__)).readlines.join - r = execute_query %Q{#{cpf_code} cpf:clean-cpf()}, { :db_name => @properties["ml.content-db"] } + cpf_code = File.read File.expand_path('../xquery/cpf.xqy', __FILE__) + r = execute_query %Q{#{cpf_code} cpf:clean-cpf()}, :db_name => @properties["ml.content-db"] end def xcc - if (!@xcc) - password_prompt - @xcc = Roxy::Xcc.new({ - :user_name => @ml_username, - :password => @ml_password, - :xcc_server => @hostname, - :xcc_port => @properties["ml.xcc-port"], - :logger => logger - }) - end - @xcc + @xcc ||= + begin + password_prompt + @xcc = Roxy::Xcc.new({ + :user_name => @ml_username, + :password => @ml_password, + :xcc_server => @hostname, + :xcc_port => @properties["ml.xcc-port"], + :logger => logger + }) + end end def get_config - if (@config == nil) then - @config = build_config @options[:config_file] - end - @config + @config ||= build_config(@options[:config_file]) end def execute_query_4(query, properties) r = go "http://#{@hostname}:#{@bootstrap_port}/use-cases/eval2.xqy", "post", {}, { :queryInput => query } - return r end def get_any_db_id r = go "http://#{@hostname}:#{@bootstrap_port}/manage/LATEST/databases?format=xml", "get" - if (r.code.to_i == 200) then - dbid = $1 if r.body =~ /.*([^<]+)<\/idref>.*/ - return dbid - end - return nil + return nil unless r.code.to_i == 200 + dbid = $1 if r.body =~ /.*([^<]+)<\/idref>.*/ end def get_db_id(db_name) r = go "http://#{@hostname}:#{@bootstrap_port}/manage/LATEST/databases?format=xml", "get" - if (r.code.to_i == 200) then - use_next_line = false - r.body.split("\n").each do |line| - if (use_next_line == true) then - dbid = $1 if line =~ /.*([^<]+)<\/idref>.*/ - return dbid - end - if (line.match(db_name)) then - use_next_line = true - end + return nil unless r.code.to_i == 200 + + use_next_line = false + r.body.split("\n").each do |line| + if use_next_line == true + dbid = $1 if line =~ /.*([^<]+)<\/idref>.*/ + return dbid end + + use_next_line = true if line.match(db_name) end - return nil + + nil end def get_sid(app_name) r = go "http://#{@hostname}:#{@bootstrap_port}/manage/LATEST/servers?format=xml", "get" - if (r.code.to_i == 200) then - previous_line = "" - r.body.split("\n").each do |line| - if (line.match("#{app_name}")) then - dbid = $1 if previous_line =~ /.*([^<]+)<\/idref>.*/ - return dbid - end + return nil unless r.code.to_i == 200 - previous_line = line + previous_line = "" + r.body.split("\n").each do |line| + if line.match "#{app_name}" + dbid = $1 if previous_line =~ /.*([^<]+)<\/idref>.*/ + return dbid end + + previous_line = line end - return nil + + nil end def execute_query_5(query, properties = {}) @@ -843,41 +790,37 @@ def execute_query_5(query, properties = {}) # 2. A caller-specified application server # 3. An application server that is present by default # 4. Any database - if (properties[:db_name] != nil) then + if properties[:db_name] != nil db_id = get_db_id(properties[:db_name]) - elsif (properties[:app_name] != nil) then + elsif properties[:app_name] != nil sid = get_sid(properties[:app_name]) else sid = get_sid("Manage") end - if (db_id == nil && sid == nil) then - db_id = get_any_db_id - end + db_id = get_any_db_id if db_id.nil? && sid.nil? - if (db_id != nil) then - logger.debug("using dbid: #{db_id}") + if db_id.present? + logger.debug "using dbid: #{db_id}" r = go "http://#{@hostname}:#{@bootstrap_port}/qconsole/endpoints/eval.xqy", "post", {}, { :dbid => db_id, :resulttype => "text", :q => query } - logger.debug(r.body) + logger.debug r.body else - logger.debug("using sid: #{sid}") + logger.debug "using sid: #{sid}" r = go "http://#{@hostname}:#{@bootstrap_port}/qconsole/endpoints/eval.xqy", "post", {}, { :sid => sid, :resulttype => "text", :q => query } - logger.debug(r.body) + logger.debug r.body end - if (r.body.match(/\{"error"/)) then - raise ExitException.new(JSON.pretty_generate(JSON.parse(r.body))) - end + raise ExitException.new(JSON.pretty_generate(JSON.parse(r.body))) if r.body.match(/\{"error"/) - return r + r end def ServerConfig.substitute_properties(sub_me, with_me, prefix = "") @@ -885,19 +828,17 @@ def ServerConfig.substitute_properties(sub_me, with_me, prefix = "") begin needs_rescan = false sub_me.each do |k,v| - if (v.match(/\$\{basedir\}/)) then + if v.match(/\$\{basedir\}/) sub_me[k] = File.expand_path(v.sub("${basedir}", ServerConfig.pwd)) else matches = v.scan(/\$\{([^}]+)\}/) - if (matches.length > 0) then + if matches.length > 0 var = "#{prefix}#{matches[0][0]}" sub = with_me[var] - if (sub) then + if sub new_val = v.sub(/\$\{[^}]+\}/, sub) sub_me[k] = new_val - if (matches.length > 1) - needs_rescan = true - end + needs_rescan = true if matches.length > 1 else dangling_vars[k] = v end @@ -906,10 +847,12 @@ def ServerConfig.substitute_properties(sub_me, with_me, prefix = "") end end while (needs_rescan == true) - if (dangling_vars.length > 0) - raise DanglingVarsException.new(dangling_vars) + sub_me.each do |k,v| + sub_me[k] = v.xquery_safe end + raise DanglingVarsException.new(dangling_vars) if dangling_vars.length > 0 + sub_me end @@ -918,9 +861,9 @@ def ServerConfig.load_properties(properties_filename, prefix = "") File.open(properties_filename, 'r') do |properties_file| properties_file.read.each_line do |line| line.strip! - if ((line[0] != ?#) && (line[0] != ?=) && (line[0] != "")) + if (line[0] != ?#) && (line[0] != ?=) && (line[0] != "") i = line.index('=') - if (i) + if i key = prefix + line[0..i - 1].strip value = line[i + 1..-1].strip properties[key] = value @@ -933,10 +876,10 @@ def ServerConfig.load_properties(properties_filename, prefix = "") end def build_config(config_file) - config = open(config_file).readlines.join + config = File.read(config_file) # Build the triggers db if it is provided - if (@properties['ml.triggers-db']) + if @properties['ml.triggers-db'].present? config.gsub!("@ml.triggers-db-xml", %Q{ @@ -964,8 +907,8 @@ def build_config(config_file) config.gsub!("@ml.triggers-mapping", "") end - if (@properties['ml.xcc-port']) - config.gsub!("@ml.xdbc-server", + + config.gsub!("@ml.xdbc-server", %Q{ @ml.app-name-xcc @@ -974,11 +917,10 @@ def build_config(config_file) digest - }) - end + }) if @properties['ml.xcc-port'].present? # Build the schemas db if it is provided - if (@properties['ml.schemas-db']) + if @properties['ml.schemas-db'].present? config.gsub!("@ml.schemas-db-xml", %Q{ @@ -1008,9 +950,9 @@ def build_config(config_file) end # Build the test appserver and db if it is provided - if (@properties['ml.test-content-db'] && @properties['ml.test-content-db'] != "" && - @properties['ml.test-port'] && @properties['ml.test-port'] != "" && - @environment != "prod") + if @properties['ml.test-content-db'].present? && + @properties['ml.test-port'].present? && + @environment != "prod" config.gsub!("@ml.test-content-db-xml", %Q{ @@ -1028,8 +970,8 @@ def build_config(config_file) }) - if (@properties['ml.test-modules-db'] && @properties['ml.test-modules-db'] != "" && - @properties['ml.test-modules-db'] != @properties['ml.app-modules-db']) + if @properties['ml.test-modules-db'].present? && + @properties['ml.test-modules-db'] != @properties['ml.app-modules-db'] config.gsub!("@ml.test-appserver", %Q{ @@ -1068,8 +1010,8 @@ def build_config(config_file) end # Build the test modules db if it is different from the app modules db - if (@properties['ml.test-modules-db'] && @properties['ml.test-modules-db'] != "" && - @properties['ml.test-modules-db'] != @properties['ml.app-modules-db']) + if @properties['ml.test-modules-db'].present? && + @properties['ml.test-modules-db'] != @properties['ml.app-modules-db'] config.gsub!("@ml.test-modules-db-xml", %Q{ @@ -1090,12 +1032,11 @@ def build_config(config_file) config.gsub!("@ml.test-modules-db-xml", "") end - if (@properties['ml.forest-data-dir']) - config.gsub!("@ml.forest-data-dir-xml", + + config.gsub!("@ml.forest-data-dir-xml", %Q{ @ml.forest-data-dir - }) - end + }) if @properties['ml.forest-data-dir'].present? @properties.each do |k, v| config.gsub!("@#{k}", v) @@ -1107,9 +1048,7 @@ def build_config(config_file) def ServerConfig.properties(prop_file_location = "../..") default_properties_file = File.expand_path("#{prop_file_location}/default.properties", __FILE__) properties_file = File.expand_path("#{prop_file_location}/build.properties", __FILE__) - if !File.exist?(properties_file) then - raise ExitException.new("You must run ml init to configure your application.") - end + raise ExitException.new("You must run ml init to configure your application.") unless File.exist?(properties_file) properties = ServerConfig.load_properties(default_properties_file, "ml.") properties.merge!(ServerConfig.load_properties(properties_file, "ml.")) @@ -1122,9 +1061,8 @@ def ServerConfig.properties(prop_file_location = "../..") properties["environment"] = environment if environment env_properties_file = File.expand_path("#{prop_file_location}/#{environment}.properties", __FILE__) - if (File.exists?(env_properties_file)) - properties.merge!(ServerConfig.load_properties(env_properties_file, "ml.")) - end + + properties.merge!(ServerConfig.load_properties(env_properties_file, "ml.")) if File.exists? env_properties_file properties = ServerConfig.substitute_properties(properties, properties, "ml.") end diff --git a/deploy/lib/util.rb b/deploy/lib/util.rb index 2a9f2be6..f3844464 100644 --- a/deploy/lib/util.rb +++ b/deploy/lib/util.rb @@ -14,22 +14,67 @@ # limitations under the License. ############################################################################### require 'rbconfig' +require 'rexml/text' def find_arg(args = []) args.each do |arg| - if (ARGV.include?(arg)) - index = ARGV.index(arg) - ARGV.slice!(index) - return arg + ARGV.each do |a| + if a == arg || a.match("^#{arg}=") + index = ARGV.index(a) + ARGV.slice!(index) + + return arg if a == arg + + if arg.match("^--") + split = a.split '=' + return a.split("=")[1] if split.length == 2 + return arg + end + end end end nil end +def pluralize(count, singular, plural = nil) + count == 1 || count =~ /^1(\.0+)?$/ ? singular : plural +end + def is_windows? - return (Config::CONFIG['host_os'] =~ /mswin|mingw/).nil? == false + (Config::CONFIG['host_os'] =~ /mswin|mingw/).nil? == false end def path_separator is_windows? ? ";" : ":" +end + +class String + unless respond_to? :try + def try(method) + send method if respond_to? method + end + end + + def strip_heredoc + indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0 + gsub(/^[ \t]{#{indent}}/, '') + end + + def xquery_safe + REXML::Text::normalize(self).gsub(/\{/, '{{').gsub(/\}/, '}}') + end +end + +class Object + def blank? + respond_to?(:empty?) ? empty? : !self + end + + def present? + !blank? + end + + def to_b + present? && ['true', 'TRUE', 'yes', 'YES', 'y', 'Y', 't', 'T'].include?(self) + end end \ No newline at end of file diff --git a/deploy/lib/xcc.rb b/deploy/lib/xcc.rb index 4e229807..703fdce9 100644 --- a/deploy/lib/xcc.rb +++ b/deploy/lib/xcc.rb @@ -68,25 +68,25 @@ class ContentCapability INSERT = "I" UPDATE = "U" EXECUTE = "E" + ER = ["E", "R"] + RU = ["R", "U"] end class Xcc < MLClient + + attr_reader :hostname, :port + + IGNORE_EXTENSIONS = ['..', '.', '.svn', '.git', '.ds_store', 'thumbs.db'] + def initialize(options) super(options) @hostname = options[:xcc_server] @port = options[:xcc_port] - @http = Roxy::Http.new({ - :logger => @logger - }) + @http = Roxy::Http.new :logger => logger @request = {} @gmt_offset = Time.now.gmt_offset end - def go(url, verb, headers = {}, params = nil, body = nil) - headers['User-Agent'] = "Roxy RubyXCC/#{RUBY_XCC_VERSION} MarkXDBC/#{XCC_VERSION}" - super(url, verb, headers, params, body) - end - def xcc_query(options) headers = {} @@ -100,22 +100,77 @@ def xcc_query(options) r = go "http://#{options[:host]}:#{options[:port]}/eval", "post", headers, params end + def load_files(path, options = {}) + if File.exists?(path) + headers = { + 'Content-Type' => "text/xml", + 'Accept' => "text/html, text/xml, image/gif, image/jpeg, application/vnd.marklogic.sequence, application/vnd.marklogic.document, */*" + } + + data = get_files(path, options) + size = data.size + + batch_commit = options[:batch_commit] == true + logger.debug "Using Batch commit: #{batch_commit}" + data.each_with_index do |file_uri, i| + commit = ((false == batch_commit) || (i >= (size - 1))) + + target_uri = build_target_uri(file_uri, options) + url = build_load_uri(target_uri, options, commit) + logger.debug "loading: #{file_uri} => #{target_uri}" + + r = go url, "put", headers, nil, prep_body(file_uri, commit) + logger.error(r.body) unless r.code.to_i == 200 + end + + return data.length + else + logger.error "#{path} does not exist" + end + 0 + end + + def load_buffer(uri, buffer, options) + headers = { + 'Content-Type' => "text/xml", + 'Accept' => "text/html, text/xml, image/gif, image/jpeg, application/vnd.marklogic.sequence, application/vnd.marklogic.document, */*" + } + + commit = options[:commit] + commit = true if (commit == nil) + target_uri = build_target_uri(uri, options) + url = build_load_uri(target_uri, options, commit) + logger.debug "loading: #{uri} => #{target_uri}" + + r = go url, "put", headers, nil, prep_buffer(buffer, true) + logger.error(r.body) unless r.code.to_i == 200 + + 1 + end + + private + + def go(url, verb, headers = {}, params = nil, body = nil) + headers['User-Agent'] = "Roxy RubyXCC/#{RUBY_XCC_VERSION} MarkXDBC/#{XCC_VERSION}" + super(url, verb, headers, params, body) + end + def get_files(path, options = {}, data = []) - @logger.debug "getting files for #{path}" - if (File.directory?(path)) + if File.directory?(path) Dir.foreach(path) do |entry| - next if (entry == '..' || entry == '.' || entry == '.svn' || entry == '.git' || entry == '.DS_Store' || entry == "Thumbs.db" || entry == "thumbs.db") + next if IGNORE_EXTENSIONS.include?(entry.downcase) full_path = File.join(path, entry) skip = false - if (options && options[:ignore_list]) - options[:ignore_list].each do |ignore| - if full_path.match(ignore) - skip = true - break - end + + options[:ignore_list].each do |ignore| + if full_path.match(ignore) + skip = true + break end - end + end if options[:ignore_list] + next if skip == true + if File.directory?(full_path) get_files(full_path, options, data) else @@ -128,148 +183,68 @@ def get_files(path, options = {}, data = []) data end - def build_load_uri(file_uri, options, commit) - url = "http://#{@hostname}:#{@port}/insert?" - - file_uri = file_uri.sub(options[:remove_prefix] || "", "") - if (options[:add_prefix]) + def build_target_uri(file_uri, options) + target_uri = file_uri.sub(options[:remove_prefix] || "", "") + if options[:add_prefix] prefix = options[:add_prefix].chomp("/") - file_uri = prefix + file_uri + target_uri = prefix + target_uri end + target_uri + end - url << "uri=#{url_encode(file_uri)}" + def build_load_uri(target_uri, options, commit) + url = "http://#{@hostname}:#{@port}/insert?" - if (options[:locale]) - url << "&locale=#{options[:locale]}" - end + url << "uri=#{url_encode(target_uri)}" - if (options[:language]) - url << "&lang=#{options[:language]}" - end + url << "&locale=#{options[:locale]}" if options[:locale] - if (options[:namespace]) - url << "&defaultns=#{options[:namespace]}" - end + url << "&lang=#{options[:language]}" if options[:language] - if (options[:quality]) - url << "&quality=#{options[:quality]}" - end + url << "&defaultns=#{options[:namespace]}" if options[:namespace] - if (options[:repairlevel] == "none") - url << "&repair=none" - elsif(options[:repairlevel] == "full") - url << "&repair=full" - end + url << "&quality=#{options[:quality]}" if options[:quality] - if (options[:format] == "xml") - url << "&format=xml" - elsif(options[:format] == "text") - url << "&format=text" - elsif(options[:format] == "binary") - url << "&format=binary" - end - if (options[:forests]) - options[:forests].each do |forest| - url << "&placeKey=#{forest}" - end - end + url << "&repair=none" if options[:repairlevel] == "none" + url << "&repair=full" if options[:repairlevel] == "full" - if (options[:collections]) - options[:collections].each do |collection| - url << "&coll=#{collection}" - end - end + url << "&format=xml" if options[:format] == "xml" + url << "&format=text" if options[:format] == "text" + url << "&format=binary" if options[:format] == "binary" - if (options[:permissions]) - options[:permissions].each do |perm| - url << "&perm=#{perm[:capability]}#{perm[:role]}" - end - end + options[:forests].each do |forest| + url << "&placeKey=#{forest}" + end if options[:forests] + + options[:collections].each do |collection| + url << "&coll=#{collection}" + end if options[:collections] + + options[:permissions].each do |perm| + url << "&perm=#{perm[:capability]}#{perm[:role]}" + end if (options[:permissions]) url << "&tzoffset=#{@gmt_offset}" - if (options[:db]) - url << "&dbname=#{options[:db]}" - end - # "&perm=Eapp-user&perm=Rapp-user&locale=#{LOCALE}&tzoffset=-18000&dbname=#{options[:db]}" + url << "&dbname=#{options[:db]}" if options[:db] - if (false == commit) - url << "&nocommit" - end + url << "&nocommit" if false == commit url end def prep_body(path, commit) - file = open(path, "rb") - - #flag that ML server is expecting - flag = commit ? "10" : "20" - - # oh so special format that xcc needs to send - body = "0#{file.lstat.size}\r\n#{file.read}#{flag}\r\n" + prep_buffer(File.read(path), commit) end def prep_buffer(buffer, commit) #flag that ML server is expecting - flag = commit ? "10" : "20" + flag = commit ? 10 : 20 # oh so special format that xcc needs to send body = "0#{buffer.length}\r\n#{buffer}#{flag}\r\n" end - def load_files(path, options) - if (File.exists?(path)) - headers = { - 'Content-Type' => "text/xml", - 'Accept' => "text/html, text/xml, image/gif, image/jpeg, application/vnd.marklogic.sequence, application/vnd.marklogic.document, */*" - } - - data = get_files(path, options) - size = data.size - - @logger.info "Loading #{size} #{pluralize(size, "document", "documents")} from #{path} to #{@hostname}:#{@port}/#{options[:db]}" - - batch_commit = options[:batch_commit] == true - @logger.debug "Using Batch commit: #{batch_commit}" - data.each_with_index do |d, i| - commit = ((false == batch_commit) || (i >= (size - 1))) - - file_uri = d - url = build_load_uri(file_uri, options, commit) - @logger.debug "loading: #{file_uri}" - - r = go url, "put", headers, nil, prep_body(d, commit) - if (r.code.to_i != 200) - @logger.error(r.body) - end - end - else - @logger.error "#{path} does not exist" - end - end - - def load_buffer(uri, buffer, options) - headers = { - 'Content-Type' => "text/xml", - 'Accept' => "text/html, text/xml, image/gif, image/jpeg, application/vnd.marklogic.sequence, application/vnd.marklogic.document, */*" - } - - commit = options[:commit] - commit = true if (commit == nil) - url = build_load_uri(uri, options, commit) - @logger.debug "loading: #{uri}" - - r = go url, "put", headers, nil, prep_buffer(buffer, true) - if (r.code.to_i != 200) - @logger.error(r.body) - end - end - - def pluralize(count, singular, plural = nil) - ((count == 1 || count =~ /^1(\.0+)?$/) ? singular : plural) - end - end end \ No newline at end of file diff --git a/deploy/lib/xquery/setup.xqy b/deploy/lib/xquery/setup.xqy index 61a74128..cb377d3b 100644 --- a/deploy/lib/xquery/setup.xqy +++ b/deploy/lib/xquery/setup.xqy @@ -474,9 +474,9 @@ declare function setup:create-forests-from-config( $database-name as xs:string) as item()* { for $forest-config in setup:get-database-forest-configs($import-config, $database-name) - let $forest-name as xs:string? := $forest-config/as:forest-name[fn:string-length(.) > 0] - let $data-directory as xs:string? := $forest-config/as:data-directory[fn:string-length(.) > 0] - let $host-name as xs:string? := $forest-config/as:host[fn:string-length(.) > 0] + let $forest-name as xs:string? := $forest-config/as:forest-name[fn:string-length(fn:string(.)) > 0] + let $data-directory as xs:string? := $forest-config/as:data-directory[fn:string-length(fn:string(.)) > 0] + let $host-name as xs:string? := $forest-config/as:host[fn:string-length(fn:string(.)) > 0] return setup:create-forest( $forest-name, @@ -491,9 +491,9 @@ declare function setup:validate-forests-from-config( $database-name as xs:string) { for $forest-config in setup:get-database-forest-configs($import-config, $database-name) - let $forest-name as xs:string? := $forest-config/as:forest-name[fn:string-length(.) > 0] - let $data-directory as xs:string? := $forest-config/as:data-directory[fn:string-length(.) > 0] - let $host-name as xs:string? := $forest-config/as:host[fn:string-length(.) > 0] + let $forest-name as xs:string? := $forest-config/as:forest-name[fn:string-length(fn:string(.)) > 0] + let $data-directory as xs:string? := $forest-config/as:data-directory[fn:string-length(fn:string(.)) > 0] + let $host-name as xs:string? := $forest-config/as:host[fn:string-length(fn:string(.)) > 0] return setup:validate-forest( $forest-name, @@ -2287,12 +2287,12 @@ declare function setup:validate-appservers( declare function setup:create-appserver( $server-config as element(gr:http-server)) as item()* { - let $server-name as xs:string? := $server-config/gr:http-server-name[fn:string-length(.) > 0] + let $server-name as xs:string? := $server-config/gr:http-server-name[fn:string-length(fn:string(.)) > 0] return if (xdmp:servers()[xdmp:server-name(.) = $server-name]) then fn:concat("HTTP Server ", $server-name, " already exists, not recreated..") else - let $root := $server-config/gr:root[fn:string-length(.) > 0] + let $root := $server-config/gr:root[fn:string-length(fn:string(.)) > 0] let $root := if ($root) then $root else "/" let $port := xs:unsignedLong($server-config/gr:port) let $is-webdav := xs:boolean($server-config/gr:webDAV) @@ -2341,7 +2341,7 @@ declare function setup:create-appserver( declare function setup:validate-appserver( $server-config as element(gr:http-server)) as item()* { - let $server-name as xs:string? := $server-config/gr:http-server-name[fn:string-length(.) > 0] + let $server-name as xs:string? := $server-config/gr:http-server-name[fn:string-length(fn:string(.)) > 0] return if (xdmp:servers()[xdmp:server-name(.) = $server-name]) then () else @@ -2351,12 +2351,12 @@ declare function setup:validate-appserver( declare function setup:create-xdbcserver( $server-config as element(gr:xdbc-server)) as item()* { - let $server-name as xs:string? := $server-config/gr:xdbc-server-name[fn:string-length(.) > 0] + let $server-name as xs:string? := $server-config/gr:xdbc-server-name[fn:string-length(fn:string(.)) > 0] return if (xdmp:servers()[xdmp:server-name(.) = $server-name]) then fn:concat("XDBC Server ", $server-name, " already exists, not recreated..") else - let $root := $server-config/gr:root[fn:string-length(.) > 0] + let $root := $server-config/gr:root[fn:string-length(fn:string(.)) > 0] let $root := if ($root) then $root else "/" let $port := xs:unsignedLong($server-config/gr:port) let $database-id := @@ -2394,7 +2394,7 @@ declare function setup:create-xdbcserver( declare function setup:validate-xdbcserver( $server-config as element(gr:xdbc-server)) as item()* { - let $server-name as xs:string? := $server-config/gr:xdbc-server-name[fn:string-length(.) > 0] + let $server-name as xs:string? := $server-config/gr:xdbc-server-name[fn:string-length(fn:string(.)) > 0] return if (xdmp:servers()[xdmp:server-name(.) = $server-name]) then () else @@ -2440,7 +2440,7 @@ declare function setup:validate-appservers-settings( declare function setup:configure-http-server( $server-config as element(gr:http-server)) as item()* { - let $server-name as xs:string? := $server-config/gr:http-server-name[fn:string-length(.) > 0] + let $server-name as xs:string? := $server-config/gr:http-server-name[fn:string-length(fn:string(.)) > 0] let $server-id := xdmp:server($server-name) let $admin-config := setup:configure-server($server-config, $server-id) return @@ -2478,7 +2478,7 @@ declare function setup:configure-http-server( xdmp:database($server-config/gr:modules/@name) else 0 - let $root := $server-config/gr:root[fn:string-length(.) > 0] + let $root := $server-config/gr:root[fn:string-length(fn:string(.)) > 0] let $root := if ($root) then $root else "/" let $admin-config := @@ -2494,40 +2494,47 @@ declare function setup:configure-http-server( let $admin-config := admin:appserver-set-root($admin-config, $server-id, $root) - let $value := $server-config/gr:session-timeout[fn:string-length(.) > 0] + let $value := $server-config/gr:session-timeout[fn:string-length(fn:string(.)) > 0] let $admin-config := if ($value) then admin:appserver-set-session-timeout($admin-config, $server-id, $value) else $admin-config - let $value := $server-config/gr:static-expires[fn:string-length(.) > 0] + let $value := $server-config/gr:static-expires[fn:string-length(fn:string(.)) > 0] let $admin-config := if ($value) then admin:appserver-set-static-expires($admin-config, $server-id, $value) else $admin-config + let $value := $server-config/gr:rewrite-resolves-globally[fn:string-length(fn:string(.)) > 0] + let $admin-config := + if ($value) then + xdmp:value("admin:appserver-set-rewrite-resolves-globally($admin-config, $server-id, $value)") + else + $admin-config + let $admin-config := admin:appserver-set-default-user($admin-config, $server-id, $default-user) let $admin-config := if ($is-webdav) then - let $value := $server-config/gr:compute-content-length[fn:string-length(.) > 0] + let $value := $server-config/gr:compute-content-length[fn:string-length(fn:string(.)) > 0] return if ($value) then admin:appserver-set-compute-content-length($admin-config, $server-id, $value) else $admin-config else - let $value := $server-config/gr:error-handler[fn:string-length(.) > 0] + let $value := $server-config/gr:error-handler[fn:string-length(fn:string(.)) > 0] let $admin-config := if ($value) then admin:appserver-set-error-handler($admin-config, $server-id, $value) else $admin-config - let $value := $server-config/gr:url-rewriter[fn:string-length(.) > 0] + let $value := $server-config/gr:url-rewriter[fn:string-length(fn:string(.)) > 0] let $admin-config := if ($value) then admin:appserver-set-url-rewriter($admin-config, $server-id, $value) @@ -2562,7 +2569,7 @@ declare function setup:configure-http-server( declare function setup:validate-http-server( $server-config as element(gr:http-server)) as item()* { - let $server-name as xs:string? := $server-config/gr:http-server-name[fn:string-length(.) > 0] + let $server-name as xs:string? := $server-config/gr:http-server-name[fn:string-length(fn:string(.)) > 0] let $server-id := xdmp:server($server-name) let $admin-config := admin:get-configuration() let $default-user := @@ -2585,7 +2592,7 @@ declare function setup:validate-http-server( xdmp:database($server-config/gr:modules/@name) else 0 - let $root := $server-config/gr:root[fn:string-length(.) > 0] + let $root := $server-config/gr:root[fn:string-length(fn:string(.)) > 0] let $root := if ($root) then $root else "/" return @@ -2617,14 +2624,14 @@ declare function setup:validate-http-server( else setup:validation-fail(fn:concat("Appserver root mismatch: ", $root, " != ", $actual)), - let $expected := $server-config/gr:session-timeout[fn:string-length(.) > 0] + let $expected := $server-config/gr:session-timeout[fn:string-length(fn:string(.)) > 0] let $actual := admin:appserver-get-session-timeout($admin-config, $server-id) return if ($expected = $actual) then () else setup:validation-fail(fn:concat("Appserver session timeout mismatch: ", $expected, " != ", $actual)), - let $expected := $server-config/gr:static-expires[fn:string-length(.) > 0] + let $expected := $server-config/gr:static-expires[fn:string-length(fn:string(.)) > 0] let $actual := admin:appserver-get-static-expires($admin-config, $server-id) return if ($expected = $actual) then () @@ -2638,7 +2645,7 @@ declare function setup:validate-http-server( setup:validation-fail(fn:concat("Appserver default user mismatch: ", $default-user, " != ", $actual)), if ($is-webdav) then - let $expected := $server-config/gr:compute-content-length[fn:string-length(.) > 0] + let $expected := $server-config/gr:compute-content-length[fn:string-length(fn:string(.)) > 0] let $actual := admin:appserver-get-compute-content-length($admin-config, $server-id) return if ($expected = $actual) then () @@ -2646,14 +2653,14 @@ declare function setup:validate-http-server( setup:validation-fail(fn:concat("Appserver compute content length mismatch: ", $expected, " != ", $actual)) else ( - let $expected := $server-config/gr:error-handler[fn:string-length(.) > 0] + let $expected := $server-config/gr:error-handler[fn:string-length(fn:string(.)) > 0] let $actual := admin:appserver-get-error-handler($admin-config, $server-id) return if ($expected = $actual) then () else setup:validation-fail(fn:concat("Appserver error handler mismatch: ", $expected, " != ", $actual)), - let $expected := $server-config/gr:url-rewriter[fn:string-length(.) > 0] + let $expected := $server-config/gr:url-rewriter[fn:string-length(fn:string(.)) > 0] let $actual := admin:appserver-get-url-rewriter($admin-config, $server-id) return if ($expected = $actual) then () @@ -2666,7 +2673,7 @@ declare function setup:validate-http-server( declare function setup:configure-xdbc-server( $server-config as element(gr:xdbc-server)) as item()* { - let $server-name as xs:string? := $server-config/gr:xdbc-server-name[fn:string-length(.) > 0] + let $server-name as xs:string? := $server-config/gr:xdbc-server-name[fn:string-length(fn:string(.)) > 0] return (: reconnect databases in case the appserver already existed :) let $database-id := @@ -2702,7 +2709,7 @@ declare function setup:configure-xdbc-server( declare function setup:validate-xdbc-server( $server-config as element(gr:xdbc-server)) as item()* { - let $server-id := xdmp:server($server-config/gr:xdbc-server-name[fn:string-length(.) > 0]) + let $server-id := xdmp:server($server-config/gr:xdbc-server-name[fn:string-length(fn:string(.)) > 0]) let $admin-config := admin:get-configuration() return ( @@ -2824,7 +2831,7 @@ declare function setup:configure-server( if ($setting/@value) then fn:data(xdmp:value($setting/@value)) else - fn:data(xdmp:value(fn:concat("$server-config/gr:", $setting, "[fn:string-length(.) > 0]"))) + fn:data(xdmp:value(fn:concat("$server-config/gr:", $setting, "[fn:string-length(fn:string(.)) > 0]"))) where (fn:exists($value)) return xdmp:set($admin-config, @@ -2900,7 +2907,7 @@ declare function setup:validate-server( output-encoding for $setting in $settings/*:setting - let $expected := fn:data(xdmp:value(fn:concat("$server-config/gr:", $setting, "[fn:string-length(.) > 0]"))) + let $expected := fn:data(xdmp:value(fn:concat("$server-config/gr:", $setting, "[fn:string-length(fn:string(.)) > 0]"))) let $actual := xdmp:value(fn:concat("admin:appserver-get-", $setting, "($admin-config, $server-id)")) where $expected return @@ -2990,132 +2997,149 @@ declare function setup:create-roles( let $role-names as xs:string* := $role/sec:role-names/sec:role-name let $permissions as element(sec:permission)* := $role/sec:permissions/* let $collections as xs:string* := $role/sec:collections/* - let $privileges as element(sec:privilege)* := $role/sec:privileges/* + let $privileges as element(sec:privilege)* := $role/sec:privileges/sec:privilege let $amps as element(sec:amp)* := $role/sec:amps/* let $eval-options := {$default-security} return - (: if the role exists, then update it :) - if (setup:get-roles(())/sec:role[sec:role-name = $role-name]) then + ( + (: if the role exists, then don't create it :) + if (setup:get-roles(())/sec:role[sec:role-name = $role-name]) then () + else ( xdmp:eval( 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; declare variable $role-name as xs:string external; declare variable $description as xs:string external; - sec:role-set-description($role-name, $description)', + declare variable $collections as element() external; + sec:create-role($role-name, $description, (), (), $collections/*)', (xs:QName("role-name"), $role-name, - xs:QName("description"), fn:string($description)), + xs:QName("description"), fn:string($description), + xs:QName("collections"), {for $c in $collections return {$c}}), $eval-options), - if ($role-names) then - xdmp:eval( - 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; - declare variable $role-name as xs:string external; - declare variable $role-names as element() external; - sec:role-set-roles($role-name, $role-names/*)', - (xs:QName("role-name"), $role-name, - xs:QName("role-names"), {for $r in $role-names return {$r}}), - $eval-options) - else (), + setup:add-rollback("roles", $role) + ), - if ($permissions) then - xdmp:eval( - 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; - declare variable $role-name as xs:string external; - declare variable $permissions as element() external; - sec:role-set-default-permissions($role-name, $permissions/*)', - ( - xs:QName("role-name"), $role-name, - xs:QName("permissions"), - - { - for $p in $permissions - return - xdmp:permission($p/sec:role-name, $p/sec:capability) - } - - ), - $eval-options) - else (), + xdmp:eval( + 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; + declare variable $role-name as xs:string external; + declare variable $description as xs:string external; + sec:role-set-description($role-name, $description)', + (xs:QName("role-name"), $role-name, + xs:QName("description"), fn:string($description)), + $eval-options), + if ($role-names) then + xdmp:eval( + 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; + declare variable $role-name as xs:string external; + declare variable $role-names as element() external; + sec:role-set-roles($role-name, $role-names/*)', + (xs:QName("role-name"), $role-name, + xs:QName("role-names"), {for $r in $role-names return {$r}}), + $eval-options) + else (), - if ($collections) then - xdmp:eval( - 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; - declare variable $role-name as xs:string external; - declare variable $collections as element() external; - sec:role-set-default-collections($role-name, $collections/*)', - (xs:QName("role-name"), $role-name, - xs:QName("collections"), {for $c in $collections return {$c}}), - $eval-options) - else (), + if ($permissions) then + xdmp:eval( + 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; + declare variable $role-name as xs:string external; + declare variable $permissions as element() external; + sec:role-set-default-permissions($role-name, $permissions/*)', + ( + xs:QName("role-name"), $role-name, + xs:QName("permissions"), + + { + for $p in $permissions + return + xdmp:eval(' + declare variable $p external; - for $privilege in $privileges - let $priv := setup:get-privilege-by-name($privilege/sec:privilege-name) - return - xdmp:eval( - 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; - declare variable $action as xs:string external; - declare variable $kind as xs:string external; - declare variable $role-name as xs:string external; - sec:privilege-add-roles($action, $kind, $role-name)', - (xs:QName("action"), $priv/sec:action, - xs:QName("kind"), $priv/sec:kind, - xs:QName("role-name"), $role-name), - $eval-options), + xdmp:permission($p/sec:role-name, $p/sec:capability)', + (xs:QName("p"), $p)) + } + + ), + $eval-options) + else (), - for $amp in $amps - return - xdmp:eval( - 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; - declare variable $namespace as xs:string external; - declare variable $local-name as xs:string external; - declare variable $document-uri as xs:string external; - declare variable $database as xs:unsignedLong external; - declare variable $role-name as xs:string external; - sec:amp-add-roles($namespace, $local-name, $document-uri, $database, $role-name)', - (xs:QName("namespace"), $amp/sec:namespace, - xs:QName("local-name"), $amp/sec:local-name, - xs:QName("document-uri"), $amp/sec:document-uri, - xs:QName("database"), if ($amp/sec:database-name eq "filesystem") then 0 else xdmp:database($amp/sec:database-name), - xs:QName("role-name"), $role-name), - $eval-options) - ) - (: role is new. create it :) - else - ( + if ($collections) then xdmp:eval( 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; declare variable $role-name as xs:string external; - declare variable $description as xs:string external; declare variable $collections as element() external; - sec:create-role($role-name, $description, (), (), $collections/*)', + sec:role-set-default-collections($role-name, $collections/*)', (xs:QName("role-name"), $role-name, - xs:QName("description"), fn:string($description), xs:QName("collections"), {for $c in $collections return {$c}}), + $eval-options) + else (), + + for $privilege in $privileges + let $priv := setup:get-privilege-by-name($privilege/sec:privilege-name) + let $validate-privilege := + if ($priv) then xdmp:log(text { "privilege is valid", $privilege/sec:privilege-name }) + else + fn:error( + xs:QName("INVALID-PRIVILEGE"), + fn:concat( + "Invalid privilege '", + $privilege/sec:privilege-name, + "' specified for role: ", + $role-name)) + return + xdmp:eval( + 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; + declare variable $action as xs:string external; + declare variable $kind as xs:string external; + declare variable $role-name as xs:string external; + sec:privilege-add-roles($action, $kind, $role-name)', + (xs:QName("action"), $priv/sec:action, + xs:QName("kind"), $priv/sec:kind, + xs:QName("role-name"), $role-name), $eval-options), - setup:add-rollback("roles", $role) - ) + + for $amp in $amps + return + xdmp:eval( + 'import module namespace sec="http://marklogic.com/xdmp/security" at "/MarkLogic/security.xqy"; + declare variable $namespace as xs:string external; + declare variable $local-name as xs:string external; + declare variable $document-uri as xs:string external; + declare variable $database as xs:unsignedLong external; + declare variable $role-name as xs:string external; + sec:amp-add-roles($namespace, $local-name, $document-uri, $database, $role-name)', + (xs:QName("namespace"), $amp/sec:namespace, + xs:QName("local-name"), $amp/sec:local-name, + xs:QName("document-uri"), $amp/sec:document-uri, + xs:QName("database"), if ($amp/sec:database-name eq "filesystem") then 0 else xdmp:database($amp/sec:database-name), + xs:QName("role-name"), $role-name), + $eval-options) + ) }; declare function setup:validate-roles( $import-config as element(configuration)) { - for $role in $import-config//sec:roles/sec:role + for $role in $import-config/sec:roles/sec:role let $role-name as xs:string := $role/sec:role-name let $description as xs:string? := $role/sec:description let $role-names as xs:string* := $role/sec:role-names/sec:role-name - let $permissions as element(sec:permission)* := $role/sec:permissions/* + let $permissions as element(sec:permission)* := $role/sec:permissions/sec:permission let $collections as xs:string* := $role/sec:collections/* - let $privileges as element(sec:privilege)* := $role/sec:privileges/* + let $privileges as element(sec:privilege)* := $role/sec:privileges/sec:privilege let $amps as element(sec:amp)* := $role/sec:amps/* let $match := setup:get-roles(())/sec:role[sec:role-name = $role-name] + let $_ := xdmp:log($match) return (: if the role exists, then update it :) if ($match) then if ($match/sec:role-name != $role-name or $match/sec:description != $description or - $match/sec:role-names/sec:role-name != $role-names) then + $match/sec:role-names/sec:role-name != $role-names or + fn:count($match/sec:permissions/sec:permission) != fn:count($permissions) or + fn:count($match/sec:privileges/sec:privilege) != fn:count($privileges)) then setup:validation-fail(fn:concat("Mismatched role: ", $role-name)) else () else @@ -3816,7 +3840,7 @@ declare function setup:get-databases-from-config( declare function setup:get-database-name-from-database-config( $db-config as element(db:database)) as xs:string? { - $db-config/db:database-name[fn:string-length(.) > 0] + $db-config/db:database-name[fn:string-length(fn:string(.)) > 0] }; declare function setup:get-forests-per-host-from-database-config( diff --git a/deploy/sample/build.sample.properties b/deploy/sample/build.sample.properties index 3554d51c..61cb8a84 100644 --- a/deploy/sample/build.sample.properties +++ b/deploy/sample/build.sample.properties @@ -68,6 +68,11 @@ authentication-method=digest # # default-user=${app-name}-user +# +# The password assigned to the default user for your application +# +appuser-password=random + # # the uris or IP addresses of your servers # WARNING: if you are running these scripts on WINDOWS you may need to change localhost to 127.0.0.1 diff --git a/deploy/sample/ml-config.sample.xml b/deploy/sample/ml-config.sample.xml index a46b4514..2962bb66 100644 --- a/deploy/sample/ml-config.sample.xml +++ b/deploy/sample/ml-config.sample.xml @@ -337,7 +337,7 @@ @ml.app-name-user A user for the @ml.app-name application - password + @ml.appuser-password @ml.app-role