Add run_cmd class method to ActiveRecord::Tasks::DatabaseTasks

-   Added run_cmd() class method to dry up Kernel.system() messages within
      this namespace and avoid shell expansion by passing a list of
      arguments instead of a string

  -   Update structure_dump, structure_load, and related tests units to
      pass a list of params instead of using a string to
      avoid shell expansion
This commit is contained in:
starbelly 2015-08-01 16:48:56 -05:00
parent c7a9f572d1
commit 07f8a96aa1
4 changed files with 39 additions and 17 deletions

@ -1,3 +1,11 @@
* Added run_cmd class method to ActiveRecord::Tasks::DatabaseTasks for
drying up Kernel.system() calls within this namespace and to avoid
shell expansion by using a paramter list instead of string as arguments
for Kernel.system(). Thanks to Nate Berkopec for supply patch to get
test units passing.
*Bryan Paxton*
* Properly allow uniqueness validations on primary keys.
Fixes #20966.

@ -252,6 +252,19 @@ def load_seed
end
end
def self.run_cmd(cmd, args, action)
fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
end
def run_cmd_error(cmd, args, action)
msg = "failed to execute:\n"
msg << "#{cmd} #{args.join(' ')}\n\n"
msg << "Please check that `#{cmd}` is :\n"
msg << " - present on this system\n"
msg << " - in your PATH\n"
msg << " - has proper permissions\n\n"
end
private
def class_for_adapter(adapter)

@ -1,5 +1,3 @@
require 'shellwords'
module ActiveRecord
module Tasks # :nodoc:
class PostgreSQLDatabaseTasks # :nodoc:
@ -55,19 +53,22 @@ def structure_dump(filename)
when String
ActiveRecord::Base.dump_schemas
end
args = ['-i', '-s', '-x', '-O', '-f', filename]
unless search_path.blank?
search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
end
command = "pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
raise 'Error dumping database' unless Kernel.system(command)
args << search_path.split(',').map do |part|
"--schema=#{part.strip}"
end.join(' ')
end
args << configuration['database']
ActiveRecord::Tasks::DatabaseTasks.run_cmd('pg_dump', args, 'dumping')
File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
end
def structure_load(filename)
set_psql_env
Kernel.system("psql -X -q -f #{Shellwords.escape(filename)} #{configuration['database']}")
def structure_load(filename)
set_psql_env
args = [ '-q', '-f', filename, configuration['database'] ]
ActiveRecord::Tasks::DatabaseTasks.run_cmd('psql', args, 'loading' )
end
private

@ -204,7 +204,7 @@ def setup
end
def test_structure_dump
Kernel.expects(:system).with("pg_dump -i -s -x -O -f #{@filename} my-app-db").returns(true)
Kernel.expects(:system).with('pg_dump', '-i', '-s', '-x', '-O', '-f', @filename, 'my-app-db').returns(true)
ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
end
@ -212,7 +212,7 @@ def test_structure_dump
def test_structure_dump_with_schema_search_path
@configuration['schema_search_path'] = 'foo,bar'
Kernel.expects(:system).with("pg_dump -i -s -x -O -f #{@filename} --schema=foo --schema=bar my-app-db").returns(true)
Kernel.expects(:system).with('pg_dump', '-i', '-s', '-x', '-O', '-f', @filename, '--schema=foo --schema=bar', 'my-app-db').returns(true)
ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
end
@ -220,7 +220,7 @@ def test_structure_dump_with_schema_search_path
def test_structure_dump_with_schema_search_path_and_dump_schemas_all
@configuration['schema_search_path'] = 'foo,bar'
Kernel.expects(:system).with("pg_dump -i -s -x -O -f #{@filename} my-app-db").returns(true)
Kernel.expects(:system).with("pg_dump", '-i', '-s', '-x', '-O', '-f', @filename, 'my-app-db').returns(true)
with_dump_schemas(:all) do
ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
@ -228,7 +228,7 @@ def test_structure_dump_with_schema_search_path_and_dump_schemas_all
end
def test_structure_dump_with_dump_schemas_string
Kernel.expects(:system).with("pg_dump -i -s -x -O -f #{@filename} --schema=foo --schema=bar my-app-db").returns(true)
Kernel.expects(:system).with("pg_dump", '-i', '-s', '-x', '-O', '-f', @filename, '--schema=foo --schema=bar', "my-app-db").returns(true)
with_dump_schemas('foo,bar') do
ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
@ -261,14 +261,14 @@ def setup
def test_structure_load
filename = "awesome-file.sql"
Kernel.expects(:system).with("psql -X -q -f #{filename} my-app-db")
Kernel.expects(:system).with('psql', '-q', '-f', filename, @configuration['database']).returns(true)
ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
end
def test_structure_load_accepts_path_with_spaces
filename = "awesome file.sql"
Kernel.expects(:system).with("psql -X -q -f awesome\\ file.sql my-app-db")
Kernel.expects(:system).with('psql', '-q', '-f', filename, @configuration['database']).returns(true)
ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename)
end