From 9c9ff31dba0aafcdfed68babd16d25a7a66e57bd Mon Sep 17 00:00:00 2001 From: Malo Skrylevo Date: Wed, 23 Nov 2022 03:16:43 +0300 Subject: [PATCH 1/2] feat: added createrole and createdb for postgres and mysql dbs + createrole and createdb for postgres and mysql dbs --- lib/capistrano-db-tasks/database.rb | 82 +++++++++++++++++++++++++++-- lib/capistrano-db-tasks/dbtasks.rb | 14 +++++ 2 files changed, 91 insertions(+), 5 deletions(-) diff --git a/lib/capistrano-db-tasks/database.rb b/lib/capistrano-db-tasks/database.rb index 08d044c..043eedd 100644 --- a/lib/capistrano-db-tasks/database.rb +++ b/lib/capistrano-db-tasks/database.rb @@ -17,9 +17,8 @@ def postgresql? %w(postgresql pg postgis chronomodel).include? @config['adapter'] end - def credentials + def credentials username = self.username credential_params = "" - username = @config['username'] || @config['user'] if mysql? credential_params << " -u #{username} " if username @@ -40,6 +39,10 @@ def database @config['database'] end + def username + @config['username'] || @config['user'] + end + def current_time Time.now.strftime("%Y-%m-%d-%H%M%S") end @@ -160,6 +163,59 @@ def db_dump_dir end end + class RemoteFake < Base + def initialize(cap_instance) + super(cap_instance) + @cap.info "[db:remote] Loading remote database config" + @cap.within @cap.release_path do + @cap.with rails_env: @cap.fetch(:rails_env) do + string = 'ra = Rails::Application;rails_config = ra::Configuration.new(ra.find_root(ra.called_from)).database_configuration' + run_string = "runner \"#{string};puts rails_config['#{fetch :rails_env}'].to_yaml\"" + config_content = + if @cap.capture(:ruby, "bin/rails -v", '2>/dev/null').size > 0 + @cap.capture(:ruby, "bin/rails #{run_string}", '2>/dev/null') + else + @cap.capture(:rails, run_string, '2>/dev/null') + end + + @config = YAML.load(config_content) + end + end + end + + def createrole + if mysql? + @cap.execute("mysql-create-user #{target_username} #{@config['password']} || true") + elsif postgresql? + @cap.execute("createuser #{credentials} -dlrs #{target_username} #{with_password} || true") + end + + self + end + + def createdb + if mysql? + @cap.execute("mysql-grant-db #{target_username} #{database} || true") + elsif postgresql? + @cap.execute("createdb #{credentials(target_username)} #{database} || true") + end + + self + end + + def with_password + @config['password'] ? "-W <<< #{@config['password']}" : "-w" + end + + def username + 'postgres' + end + + def target_username + @config['username'] || @config['user'] + end + end + class Local < Base def initialize(cap_instance) super(cap_instance) @@ -209,7 +265,7 @@ def execute(cmd) end class << self - def check(local_db, remote_db = nil) + def check(local_db = nil, remote_db = nil) return if mysql_db_valid?(local_db, remote_db) return if postgresql_db_valid?(local_db, remote_db) @@ -217,14 +273,30 @@ def check(local_db, remote_db = nil) end def mysql_db_valid?(local_db, remote_db) - local_db.mysql? && (remote_db.nil? || remote_db && remote_db.mysql?) + (local_db.nil? || local_db && local_db.mysql?) && (remote_db.nil? || remote_db && remote_db.mysql?) end def postgresql_db_valid?(local_db, remote_db) - local_db.postgresql? && + (local_db.nil? || (local_db && local_db.postgresql?)) && (remote_db.nil? || (remote_db && remote_db.postgresql?)) end + def createrole(instance) + remote_db = Database::RemoteFake.new(instance) + + check(nil, remote_db) + + remote_db.createrole + end + + def createdb(instance) + remote_db = Database::RemoteFake.new(instance) + + check(nil, remote_db) + + remote_db.createdb + end + def remote_to_local(instance) local_db = Database::Local.new(instance) remote_db = Database::Remote.new(instance) diff --git a/lib/capistrano-db-tasks/dbtasks.rb b/lib/capistrano-db-tasks/dbtasks.rb index 15891be..e985ae6 100644 --- a/lib/capistrano-db-tasks/dbtasks.rb +++ b/lib/capistrano-db-tasks/dbtasks.rb @@ -31,6 +31,20 @@ end end end + + desc 'Create rails DB role on remote server' + task :createrole do + on roles(:db) do + Database.createrole(self) + end + end + + desc 'Create rails DB database on remote server' + task createdb: :createrole do + on roles(:db) do + Database.createdb(self) + end + end end namespace :local do From 978abe880e40dfaf9a85f62215b5f6c747cfb185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C2=ABMalo=C2=BB=20Skrylev?= Date: Tue, 17 Oct 2023 23:19:09 +0300 Subject: [PATCH 2/2] feat: allow supporting rvm with uncompatible versions --- lib/capistrano-db-tasks/database.rb | 37 +++++++++++++++++++---------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/lib/capistrano-db-tasks/database.rb b/lib/capistrano-db-tasks/database.rb index 043eedd..cebe692 100644 --- a/lib/capistrano-db-tasks/database.rb +++ b/lib/capistrano-db-tasks/database.rb @@ -4,6 +4,7 @@ class Base DBCONFIG_END_FLAG = "__CAPISTRANODB_CONFIG_END_FLAG__".freeze attr_accessor :config, :output_file + attr_reader :rvm_ruby def initialize(cap_instance) @cap = cap_instance @@ -59,6 +60,28 @@ def compressor end end + def with_rvm? + @rvm_ruby ||= @cap.capture(:rvm, "current", '2>/dev/null') + + !@rvm_ruby.empty? + end + + def run_with_rvm run_string + if @cap.capture(:rvm, rvm_ruby, "do", "bin/rails -v", '2>/dev/null').size > 0 + @cap.capture(:rvm, rvm_ruby, "do", "bin/rails #{run_string}") + else + @cap.capture(:rvm, rvm_ruby, "do", "rails", run_string, '2>/dev/null') + end + end + + def run_plain run_string + if @cap.capture(:ruby, "bin/rails -v", '2>/dev/null').size > 0 + @cap.capture(:ruby, "bin/rails #{run_string}") + else + @cap.capture(:rails, run_string, '2>/dev/null') + end + end + private def pgpass @@ -112,12 +135,7 @@ def initialize(cap_instance) @cap.within @cap.current_path do @cap.with rails_env: @cap.fetch(:rails_env) do run_string = "runner \"puts '#{DBCONFIG_BEGIN_FLAG}' + ActiveRecord::Base.connection.instance_variable_get(:@config).to_yaml + '#{DBCONFIG_END_FLAG}'\"" - dirty_config_content = - if @cap.capture(:ruby, "bin/rails -v", '2>/dev/null').size > 0 - @cap.capture(:ruby, "bin/rails #{run_string}", '2>/dev/null') - else - @cap.capture(:rails, run_string, '2>/dev/null') - end + dirty_config_content = with_rvm? ? run_with_rvm(run_string) : run_plain(run_string) # Remove all warnings, errors and artefacts produced by bunlder, rails and other useful tools config_content = dirty_config_content.match(/#{DBCONFIG_BEGIN_FLAG}(.*?)#{DBCONFIG_END_FLAG}/m)[1] @config = YAML.load(config_content).each_with_object({}) { |(k, v), h| h[k.to_s] = v } @@ -171,12 +189,7 @@ def initialize(cap_instance) @cap.with rails_env: @cap.fetch(:rails_env) do string = 'ra = Rails::Application;rails_config = ra::Configuration.new(ra.find_root(ra.called_from)).database_configuration' run_string = "runner \"#{string};puts rails_config['#{fetch :rails_env}'].to_yaml\"" - config_content = - if @cap.capture(:ruby, "bin/rails -v", '2>/dev/null').size > 0 - @cap.capture(:ruby, "bin/rails #{run_string}", '2>/dev/null') - else - @cap.capture(:rails, run_string, '2>/dev/null') - end + config_content = with_rvm? ? run_with_rvm(run_string) : run_plain(run_string) @config = YAML.load(config_content) end