db-evolve 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/tasks/db.rb +120 -8
- data/lib/tasks/sql_color.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8abf7748fc2f2f9425e4d63c7656593de7fb889b
|
4
|
+
data.tar.gz: 4a30a774c669bcc6493213269ec75b770ab1b579
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 833c3994a6603bf1cb55f78d9432d67459c54274017dc33ea4c19ed1e48dd67772f3c036ff0f9e951a188896c93c2f890491c703fe6d6b5a91b22ca2a25e41e0
|
7
|
+
data.tar.gz: a2725c132f67375b5c7e955f4da020dd4efb31c14ef5dff07a91f928f4f28aaae176f189252e1a5c7dfc08d8ae43ceceb391ab94ee9b2b5a535aaccc99463e86
|
data/lib/tasks/db.rb
CHANGED
@@ -47,6 +47,34 @@ namespace :db do
|
|
47
47
|
|
48
48
|
end
|
49
49
|
|
50
|
+
$i_nagged = false
|
51
|
+
|
52
|
+
def build_real_connection_config to_exec: false, noop: false
|
53
|
+
require 'pg'
|
54
|
+
if to_exec
|
55
|
+
config_name = "#{Rails.env}_dbevolve"
|
56
|
+
if Rails.configuration.database_configuration[config_name].present?
|
57
|
+
config = Rails.configuration.database_configuration[config_name].clone
|
58
|
+
else
|
59
|
+
config = ActiveRecord::Base.connection_config.clone
|
60
|
+
unless $i_nagged || noop || Rails.env=='development'
|
61
|
+
puts "Your database.yml file does not contain an entry for '#{config_name}', so we're using '#{Rails.env}'. This works if your database user has permission to edit your schema, but this is not recommended outside of development. For more information visit: https://github.com/keredson/ruby-db-evolve/blob/master/README.md#schema-change-permissions"
|
62
|
+
$i_nagged = true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
else
|
66
|
+
config = ActiveRecord::Base.connection_config.clone
|
67
|
+
end
|
68
|
+
config.delete(:adapter)
|
69
|
+
config.delete(:pool)
|
70
|
+
config[:dbname] = config.delete(:database)
|
71
|
+
config[:user] = config.delete(:username) || ENV['USER'] || ENV['USERNAME']
|
72
|
+
return config
|
73
|
+
end
|
74
|
+
|
75
|
+
def build_real_connection to_exec: false, noop: false
|
76
|
+
return PG::Connection.open(build_real_connection_config to_exec: to_exec, noop: noop)
|
77
|
+
end
|
50
78
|
|
51
79
|
def do_evolve(noop, yes, nowait)
|
52
80
|
existing_tables, existing_indexes = load_existing_tables()
|
@@ -74,6 +102,8 @@ def do_evolve(noop, yes, nowait)
|
|
74
102
|
|
75
103
|
to_run += calc_index_changes(existing_indexes, $schema_indexes, renames, rename_cols_by_table)
|
76
104
|
|
105
|
+
to_run += calc_perms_changes($schema_tables, noop) unless $check_perms_for.empty?
|
106
|
+
|
77
107
|
to_run += sql_drops(deletes)
|
78
108
|
|
79
109
|
# prompt and execute
|
@@ -97,7 +127,7 @@ def do_evolve(noop, yes, nowait)
|
|
97
127
|
return
|
98
128
|
end
|
99
129
|
|
100
|
-
config =
|
130
|
+
config = build_real_connection_config to_exec: true
|
101
131
|
puts "Connecting to database:"
|
102
132
|
config.each do |k,v|
|
103
133
|
next if k==:password
|
@@ -108,11 +138,6 @@ def do_evolve(noop, yes, nowait)
|
|
108
138
|
print "Run this SQL? (type yes or no) "
|
109
139
|
end
|
110
140
|
if yes || STDIN.gets.strip=='yes'
|
111
|
-
require 'pg'
|
112
|
-
config = ActiveRecord::Base.connection_config
|
113
|
-
config.delete(:adapter)
|
114
|
-
config[:dbname] = config.delete(:database)
|
115
|
-
config[:user] = config.delete(:username)
|
116
141
|
if !nowait
|
117
142
|
print "\nExecuting in "
|
118
143
|
[3,2,1].each do |c|
|
@@ -121,7 +146,7 @@ def do_evolve(noop, yes, nowait)
|
|
121
146
|
end
|
122
147
|
end
|
123
148
|
puts
|
124
|
-
conn =
|
149
|
+
conn = build_real_connection to_exec: true
|
125
150
|
to_run.each do |sql|
|
126
151
|
puts SQLColor.colorize(sql)
|
127
152
|
conn.exec(sql)
|
@@ -172,6 +197,43 @@ def calc_index_changes(existing_indexes, schema_indexes, table_renames, rename_c
|
|
172
197
|
return to_run
|
173
198
|
end
|
174
199
|
|
200
|
+
def get_db_username
|
201
|
+
username = ActiveRecord::Base.connection_config[:username] || ENV['USER'] || ENV['USERNAME']
|
202
|
+
return username
|
203
|
+
end
|
204
|
+
|
205
|
+
def calc_perms_changes schema_tables, noop
|
206
|
+
username = get_db_username
|
207
|
+
users = ($check_perms_for.map { |user| ActiveRecord::Base::sanitize(user) }).join ","
|
208
|
+
database = ActiveRecord::Base.connection_config[:database]
|
209
|
+
sql = %{
|
210
|
+
select grantee, table_name, privilege_type
|
211
|
+
from information_schema.role_table_grants
|
212
|
+
where table_catalog=#{ActiveRecord::Base::sanitize(database)}
|
213
|
+
and grantee in (#{users})
|
214
|
+
and table_schema='public';
|
215
|
+
}
|
216
|
+
results = build_real_connection(noop: noop).exec(sql)
|
217
|
+
existing_perms = Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = Set.new } }
|
218
|
+
results.each do |row|
|
219
|
+
existing_perms[row['grantee']][row['table_name']].add(row['privilege_type'])
|
220
|
+
end
|
221
|
+
to_run = []
|
222
|
+
schema_tables.each do |table_name, tbl|
|
223
|
+
$check_perms_for.each do |user|
|
224
|
+
to_grant = (tbl.perms_for_user[user] - existing_perms[user][table_name]).to_a
|
225
|
+
to_revoke = (existing_perms[user][table_name] - tbl.perms_for_user[user]).to_a
|
226
|
+
to_run.push("GRANT "+ to_grant.join(',') +" ON #{escape_table(table_name)} TO #{user}") unless to_grant.empty?
|
227
|
+
to_run.push("REVOKE "+ to_revoke.join(',') +" ON #{escape_table(table_name)} FROM #{user}") unless to_revoke.empty?
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
if !to_run.empty?
|
232
|
+
to_run.unshift("\n-- update permissions")
|
233
|
+
end
|
234
|
+
|
235
|
+
return to_run
|
236
|
+
end
|
175
237
|
|
176
238
|
|
177
239
|
IgnoreTables = Set.new ["schema_migrations"]
|
@@ -196,12 +258,28 @@ end
|
|
196
258
|
|
197
259
|
|
198
260
|
class Table
|
199
|
-
attr_accessor :name, :opts, :id, :columns
|
261
|
+
attr_accessor :name, :opts, :id, :columns, :perms_for_user
|
200
262
|
|
201
263
|
def initialize()
|
202
264
|
@columns = []
|
203
265
|
end
|
204
266
|
|
267
|
+
def grant *args, to: nil
|
268
|
+
to = get_db_username if to.nil?
|
269
|
+
$check_perms_for.add(to)
|
270
|
+
args.each do |arg|
|
271
|
+
@perms_for_user[to] |= check_perm(arg)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def revoke *args, from: nil
|
276
|
+
from = get_db_username if from.nil?
|
277
|
+
$check_perms_for.add(from)
|
278
|
+
args.each do |arg|
|
279
|
+
@perms_for_user[from] -= check_perm(arg)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
205
283
|
def method_missing(method_sym, *arguments, &block)
|
206
284
|
c = Column.new
|
207
285
|
c.type = method_sym.to_s
|
@@ -233,11 +311,16 @@ end
|
|
233
311
|
|
234
312
|
$schema_tables = {}
|
235
313
|
$akas_tables = Hash.new { |h, k| h[k] = Set.new }
|
314
|
+
$check_perms_for = Set.new
|
236
315
|
|
237
316
|
def create_table(name, opts={})
|
238
317
|
tbl = Table.new
|
239
318
|
tbl.name = name
|
240
319
|
tbl.opts = opts
|
320
|
+
tbl.perms_for_user = Hash.new { |h, k| h[k] = Set.new }
|
321
|
+
$default_perms_for.each do |k,v|
|
322
|
+
tbl.perms_for_user[k] += v
|
323
|
+
end
|
241
324
|
if opts
|
242
325
|
if opts.has_key? 'id'
|
243
326
|
tbl.id = opts['id']
|
@@ -275,6 +358,32 @@ def add_index(table, columns, opts)
|
|
275
358
|
$schema_indexes.append(opts)
|
276
359
|
end
|
277
360
|
|
361
|
+
$allowed_perms = Set.new ["INSERT", "SELECT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER"]
|
362
|
+
$default_perms_for = Hash.new { |h, k| h[k] = Set.new }
|
363
|
+
|
364
|
+
def check_perm perm
|
365
|
+
perm = perm.to_s.upcase
|
366
|
+
return Set.new($allowed_perms) if perm=="ALL"
|
367
|
+
raise ArgumentError.new("permission #{perm} is not one of #{$allowed_perms.to_a}") unless $allowed_perms.include? perm
|
368
|
+
return Set.new [perm]
|
369
|
+
end
|
370
|
+
|
371
|
+
def grant(*perms, to: nil)
|
372
|
+
to = get_db_username if to.nil?
|
373
|
+
$check_perms_for.add(to)
|
374
|
+
perms.each do |perm|
|
375
|
+
$default_perms_for[to] |= check_perm(perm)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
def revoke(*perms, from: nil)
|
380
|
+
from = get_db_username if from.nil?
|
381
|
+
$check_perms_for.add(from)
|
382
|
+
perms.each do |perm|
|
383
|
+
$default_perms_for[from] -= check_perm(perm)
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
278
387
|
module DB
|
279
388
|
module Evolve
|
280
389
|
class Schema
|
@@ -355,6 +464,9 @@ def sql_adds(tables)
|
|
355
464
|
end
|
356
465
|
if !$tmp_to_run.empty?
|
357
466
|
$tmp_to_run.unshift("\n-- add tables")
|
467
|
+
if !$check_perms_for.empty?
|
468
|
+
$tmp_to_run << "REVOKE ALL ON #{(tables.map {|t| escape_table(t)}).join(',')} FROM #{$check_perms_for.to_a.join(',')}"
|
469
|
+
end
|
358
470
|
end
|
359
471
|
return $tmp_to_run
|
360
472
|
end
|
data/lib/tasks/sql_color.rb
CHANGED
@@ -15,7 +15,7 @@ class SQLColor
|
|
15
15
|
if sql.strip.start_with?('--')
|
16
16
|
return apply(CYAN, sql)
|
17
17
|
end
|
18
|
-
sql = sql.gsub(/(CREATE|ALTER|TABLE|COLUMN|ADD|TYPE|BEGIN|TRANSACTION|COMMIT| ON |INDEX|UPDATE|SET|WHERE)/){|s|apply(GREEN, s)}
|
18
|
+
sql = sql.gsub(/(CREATE|ALTER|TABLE|COLUMN|ADD|TYPE|BEGIN|TRANSACTION|COMMIT|GRANT|REVOKE| ON |INDEX|UPDATE|SET|WHERE)/){|s|apply(GREEN, s)}
|
19
19
|
sql = sql.gsub(/(DROP)/){|s|apply(RED, s)}
|
20
20
|
sql = sql.gsub(/("[^"]*")/){|s|apply(WHITE, s, bold=true)}
|
21
21
|
return sql
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: db-evolve
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derek Anderson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A diff/patch-esque tool to replace schema migrations in Ruby. See https://github.com/keredson/ruby-db-evolve
|
14
14
|
for details.
|