prick 0.2.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +6 -5
- data/Gemfile +4 -1
- data/TODO +10 -0
- data/doc/prick.txt +114 -0
- data/exe/prick +328 -402
- data/lib/ext/fileutils.rb +18 -0
- data/lib/ext/forward_method.rb +18 -0
- data/lib/ext/shortest_path.rb +44 -0
- data/lib/prick.rb +20 -10
- data/lib/prick/branch.rb +254 -0
- data/lib/prick/builder.rb +164 -0
- data/lib/prick/cache.rb +34 -0
- data/lib/prick/command.rb +19 -11
- data/lib/prick/constants.rb +122 -48
- data/lib/prick/database.rb +28 -20
- data/lib/prick/diff.rb +125 -0
- data/lib/prick/exceptions.rb +15 -3
- data/lib/prick/git.rb +77 -30
- data/lib/prick/head.rb +183 -0
- data/lib/prick/migration.rb +40 -200
- data/lib/prick/program.rb +493 -0
- data/lib/prick/project.rb +523 -351
- data/lib/prick/rdbms.rb +4 -13
- data/lib/prick/schema.rb +16 -90
- data/lib/prick/share.rb +64 -0
- data/lib/prick/state.rb +192 -0
- data/lib/prick/version.rb +62 -29
- data/libexec/strip-comments +33 -0
- data/make_releases +48 -345
- data/make_schema +10 -0
- data/prick.gemspec +14 -23
- data/share/diff/diff.after-tables.sql +4 -0
- data/share/diff/diff.before-tables.sql +4 -0
- data/share/diff/diff.tables.sql +8 -0
- data/share/migration/diff.tables.sql +8 -0
- data/share/migration/features.yml +6 -0
- data/share/migration/migrate.sql +3 -0
- data/share/migration/migrate.yml +8 -0
- data/share/migration/tables.sql +3 -0
- data/share/schema/build.yml +14 -0
- data/share/schema/schema.sql +5 -0
- data/share/schema/schema/build.yml +3 -0
- data/share/schema/schema/prick/build.yml +14 -0
- data/share/schema/schema/prick/data.sql +7 -0
- data/share/schema/schema/prick/schema.sql +5 -0
- data/share/{schemas/prick/schema.sql → schema/schema/prick/tables.sql} +2 -5
- data/{file → share/schema/schema/public/.keep} +0 -0
- data/share/schema/schema/public/build.yml +14 -0
- data/share/schema/schema/public/schema.sql +3 -0
- data/test_assorted +192 -0
- data/test_feature +112 -0
- data/test_refactor +34 -0
- data/test_single_dev +83 -0
- metadata +43 -68
- data/lib/prick/build.rb +0 -376
- data/lib/prick/migra.rb +0 -22
- data/share/schemas/prick/data.sql +0 -8
data/lib/prick/cache.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
module Prick
|
3
|
+
class Cache
|
4
|
+
def initialize
|
5
|
+
end
|
6
|
+
|
7
|
+
def exist?(version)
|
8
|
+
File.exist?(file(version))
|
9
|
+
end
|
10
|
+
|
11
|
+
def list
|
12
|
+
Dir.glob(File.join(CACHE_DIR, "*.sql.gz"))
|
13
|
+
end
|
14
|
+
|
15
|
+
def load(database, version)
|
16
|
+
Rdbms.load(database, file(version))
|
17
|
+
end
|
18
|
+
|
19
|
+
def save(database, version = database.version)
|
20
|
+
Rdbms.save(database, file(version))
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns list of removed files
|
24
|
+
def clean
|
25
|
+
l = list
|
26
|
+
FileUtils.rm(l)
|
27
|
+
l
|
28
|
+
end
|
29
|
+
|
30
|
+
def file(version)
|
31
|
+
File.join(CACHE_DIR, "#{version}.sql.gz")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/prick/command.rb
CHANGED
@@ -14,14 +14,13 @@ module Command
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
# Execute the shell command 'cmd' and return
|
18
|
-
# strings
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# :fail is true. The exit status of the last command is stored in ::status
|
17
|
+
# Execute the shell command 'cmd' and return standard output as an array of
|
18
|
+
# strings while stderr is passed through unless stderr: is false. If stderr:
|
19
|
+
# is true, it returns a tuple of [stdout, stderr] instead. The shell command
|
20
|
+
# is executed with the `errexit` and `pipefail` bash options
|
21
|
+
#
|
22
|
+
# It raises a Command::Error exception if the command fails unless :fail is
|
23
|
+
# true. The exit status of the last command is stored in ::status
|
25
24
|
#
|
26
25
|
def command(cmd, stderr: false, fail: true)
|
27
26
|
cmd = "set -o errexit\nset -o pipefail\n#{cmd}"
|
@@ -62,10 +61,19 @@ module Command
|
|
62
61
|
pr[0].close
|
63
62
|
pe[0].close
|
64
63
|
|
64
|
+
result =
|
65
|
+
case stderr
|
66
|
+
when true; [out, err]
|
67
|
+
when false; out
|
68
|
+
when NilClass; $stderr.puts err
|
69
|
+
else
|
70
|
+
raise Internal, "Unexpected value for :stderr - #{stderr.inspect}"
|
71
|
+
end
|
72
|
+
|
65
73
|
if @status == 0 || fail == false
|
66
|
-
|
67
|
-
|
68
|
-
raise Command::Error.new((out + err).join("\n") + "\n", status, out, err)
|
74
|
+
result
|
75
|
+
elsif fail
|
76
|
+
raise Command::Error.new("\n" + cmd + "\n" + (out + err).join("\n") + "\n", status, out, err)
|
69
77
|
end
|
70
78
|
end
|
71
79
|
|
data/lib/prick/constants.rb
CHANGED
@@ -1,62 +1,96 @@
|
|
1
1
|
|
2
2
|
module Prick
|
3
|
+
### DIRECTORIES AND FILE NAMES
|
4
|
+
|
3
5
|
# Shared files (part of the installation)
|
4
6
|
SHARE_PATH = "#{File.dirname(File.dirname(__dir__))}/share"
|
7
|
+
LIBEXEC_PATH = "#{File.dirname(File.dirname(__dir__))}/libexec"
|
5
8
|
|
6
9
|
# Project directories
|
7
10
|
DIRS = [
|
8
|
-
|
9
|
-
|
10
|
-
FEATURE_DIR = "features",
|
11
|
-
SCHEMA_DIR = "schemas",
|
11
|
+
MIGRATION_DIR = "migration",
|
12
|
+
SCHEMA_DIR = "schema",
|
12
13
|
PRICK_DIR = "#{SCHEMA_DIR}/prick",
|
13
14
|
PUBLIC_DIR = "#{SCHEMA_DIR}/public",
|
14
15
|
VAR_DIR = "var",
|
15
16
|
CACHE_DIR = "#{VAR_DIR}/cache",
|
17
|
+
SPOOL_DIR = "#{VAR_DIR}/spool",
|
16
18
|
TMP_DIR = "tmp",
|
17
19
|
CLONE_DIR = "tmp/clone",
|
18
20
|
SPEC_DIR = "spec"
|
19
21
|
]
|
20
22
|
|
23
|
+
# The project state file
|
24
|
+
PROJECT_STATE_FILE = ".prick-project"
|
25
|
+
PROJECT_STATE_PATH = PROJECT_STATE_FILE
|
26
|
+
|
27
|
+
# The .prick-version file
|
28
|
+
PRICK_VERSION_FILE = ".prick-version"
|
29
|
+
PRICK_VERSION_PATH = PRICK_VERSION_FILE
|
30
|
+
|
31
|
+
# The prick.versions data file. This is where the Schema saves its version
|
32
|
+
SCHEMA_VERSION_FILE = "data.sql"
|
33
|
+
SCHEMA_VERSION_PATH = File.join(PRICK_DIR, SCHEMA_VERSION_FILE)
|
34
|
+
|
35
|
+
# The the .prick-migration file
|
36
|
+
PRICK_MIGRATION_FILE = ".prick-migration"
|
37
|
+
PRICK_MIGRATION_PATH = File.join(MIGRATION_DIR, PRICK_MIGRATION_FILE)
|
38
|
+
|
39
|
+
# The the .prick-feature file
|
40
|
+
PRICK_FEATURE_FILE = ".prick-feature"
|
41
|
+
PRICK_FEATURE_PATH = File.join(MIGRATION_DIR, PRICK_FEATURE_FILE)
|
42
|
+
|
43
|
+
# The strip-comments executable
|
44
|
+
STRIP_COMMENTS_NAME = "strip-comments"
|
45
|
+
STRIP_COMMENTS_PATH = File.join(LIBEXEC_PATH, "strip-comments")
|
46
|
+
|
47
|
+
# Diff files
|
48
|
+
DIFF_FILE = "diff.sql"
|
49
|
+
BEFORE_TABLES_DIFF_NAME = "diff.before-tables.sql"
|
50
|
+
TABLES_DIFF_NAME = "diff.tables.sql"
|
51
|
+
AFTER_TABLES_DIFF_NAME = "diff.after-tables.sql"
|
52
|
+
|
53
|
+
BEFORE_TABLES_DIFF_PATH = File.join(MIGRATION_DIR, BEFORE_TABLES_DIFF_NAME)
|
54
|
+
TABLES_DIFF_PATH = File.join(MIGRATION_DIR, TABLES_DIFF_NAME)
|
55
|
+
AFTER_TABLES_DIFF_PATH = File.join(MIGRATION_DIR, AFTER_TABLES_DIFF_NAME)
|
56
|
+
|
57
|
+
TABLES_DIFF_SHARE_PATH = File.join(SHARE_PATH, "diff", TABLES_DIFF_NAME)
|
58
|
+
|
59
|
+
|
21
60
|
# Dump files
|
22
61
|
DUMP_EXT = "dump.gz"
|
23
62
|
DUMP_GLOB = "*-[0-9]*.#{DUMP_EXT}"
|
24
63
|
def self.dump_glob(project_name) "#{project_name}-*.#{DUMP_EXT}" end
|
25
64
|
|
65
|
+
### REGULAR EXPRESSIONS
|
66
|
+
|
67
|
+
# Matches a system name. System names are used for objects that are external to prick
|
68
|
+
# (like usernames)
|
69
|
+
NAME_SUB_RE = /[a-z][a-z0-9_-]*/
|
70
|
+
NAME_RE = /^#{NAME_SUB_RE}$/
|
26
71
|
|
27
72
|
# Matches an identifier. Identifiers consist of lower case letters, digits
|
28
73
|
# and underscores but not dashes because they're used as separators
|
29
74
|
IDENT_SUB_RE = /[a-z][a-z0-9_]*/
|
30
75
|
IDENT_RE = /^#{IDENT_SUB_RE}$/
|
31
76
|
|
32
|
-
# Matches an uppercase identifier
|
33
|
-
# UPCASE_IDENT_SUB_RE = /[A-Z][A-Z0-9_]*/
|
34
|
-
# UPCASE_IDENT_RE = /#{UPCASE_IDENT_SUB_RE}/
|
35
|
-
|
36
|
-
# A (system) name. Names are used for projects and usernames that are
|
37
|
-
# external to prick and can include both dashes and underscores but dashes
|
38
|
-
# have to be followed by a character and not a digit so 'ident-1234' is not
|
39
|
-
# allowed but 'ident_1234' and 'ident1234' are
|
40
|
-
NAME_SUB_RE = /#{IDENT_SUB_RE}/
|
41
|
-
NAME_RE = /^#{NAME_SUB_RE}$/
|
42
|
-
|
43
77
|
# Matches a project name
|
44
|
-
PROJECT_NAME_SUB_RE =
|
45
|
-
PROJECT_NAME_RE =
|
78
|
+
PROJECT_NAME_SUB_RE = IDENT_SUB_RE
|
79
|
+
PROJECT_NAME_RE = IDENT_RE
|
46
80
|
|
47
81
|
# Matches a custom name
|
48
|
-
CUSTOM_NAME_SUB_RE =
|
49
|
-
CUSTOM_NAME_RE =
|
82
|
+
CUSTOM_NAME_SUB_RE = IDENT_SUB_RE
|
83
|
+
CUSTOM_NAME_RE = IDENT_RE
|
50
84
|
|
51
85
|
# Matches a feature name
|
52
|
-
FEATURE_NAME_SUB_RE =
|
53
|
-
FEATURE_NAME_RE =
|
86
|
+
FEATURE_NAME_SUB_RE = /(?!initial)#{IDENT_SUB_RE}/
|
87
|
+
FEATURE_NAME_RE = /^#{FEATURE_NAME_SUB_RE}$/
|
54
88
|
|
55
89
|
# Matches a postgres user name
|
56
90
|
USER_NAME_SUB_RE = NAME_SUB_RE
|
57
91
|
USER_NAME_RE = NAME_RE
|
58
92
|
|
59
|
-
# Matches a major.minor.patch version
|
93
|
+
# Matches a major.minor.patch ('MMP') version
|
60
94
|
#
|
61
95
|
# The *_SEMVER REs are derived from the canonical RE
|
62
96
|
#
|
@@ -81,15 +115,48 @@ module Prick
|
|
81
115
|
SEMVER_SUB_RE = /#{MMP_SEMVER_SUB_RE}(?:-#{PRE_SEMVER_SUB_RE})?/
|
82
116
|
SEMVER_RE = /^#{SEMVER_SUB_RE}$/
|
83
117
|
|
84
|
-
#
|
118
|
+
# Tag RE. The general syntax for a tag is '<custom>-v<version>_<feature>'
|
85
119
|
#
|
86
120
|
# The RE defines the following captures:
|
87
121
|
# $1 - custom name, can be nil
|
88
122
|
# $2 - semantic version
|
89
123
|
# $3 - feature name, can be nil
|
90
124
|
#
|
125
|
+
TAG_SUB_RE = /
|
126
|
+
(?:(#{CUSTOM_NAME_SUB_RE})-)?
|
127
|
+
v
|
128
|
+
(#{SEMVER_SUB_RE})
|
129
|
+
(?:_(#{FEATURE_NAME_SUB_RE}))?
|
130
|
+
/x
|
131
|
+
TAG_RE = /^#{TAG_SUB_RE}$/
|
132
|
+
|
133
|
+
# TODO: Handle initial branches (0.0.0-initial)
|
134
|
+
|
135
|
+
# Branch RE. The general syntax for a branch is '<custom>-<version>_<feature>'
|
136
|
+
#
|
137
|
+
# The RE defines the following captures:
|
138
|
+
# $1 - custom name, can be nil
|
139
|
+
# $2 - semantic version
|
140
|
+
# $3 - feature name, can be nil
|
141
|
+
#
|
142
|
+
BRANCH_SUB_RE = /
|
143
|
+
(?:(#{CUSTOM_NAME_SUB_RE})-)?
|
144
|
+
(#{SEMVER_SUB_RE})
|
145
|
+
(?:_(#{FEATURE_NAME_SUB_RE}))?
|
146
|
+
/x
|
147
|
+
BRANCH_RE = /^#{BRANCH_SUB_RE}$/
|
148
|
+
|
149
|
+
# Tag or branch RE. The general syntax for a branch is '<custom>-v?<version>_<feature>'
|
150
|
+
#
|
151
|
+
# The RE defines the following captures:
|
152
|
+
# $1 - custom name, can be nil
|
153
|
+
# $2 - tag, nil or 'v'
|
154
|
+
# $3 - semantic version
|
155
|
+
# $4 - feature name, can be nil
|
156
|
+
#
|
91
157
|
VERSION_SUB_RE = /
|
92
158
|
(?:(#{CUSTOM_NAME_SUB_RE})-)?
|
159
|
+
(v)?
|
93
160
|
(#{SEMVER_SUB_RE})
|
94
161
|
(?:_(#{FEATURE_NAME_SUB_RE}))?
|
95
162
|
/x
|
@@ -113,24 +180,11 @@ module Prick
|
|
113
180
|
# $1 - custom name, can be nil
|
114
181
|
# $2 - semantic version
|
115
182
|
#
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
# Migration RE. The syntax is <version>_<version>
|
123
|
-
#
|
124
|
-
# The RE defines the following captures
|
125
|
-
# $1 - from version
|
126
|
-
# $2 - from custom name, can be nil
|
127
|
-
# $3 - from semantic version
|
128
|
-
# $4 - to version
|
129
|
-
# $5 - to custom name, can be nil
|
130
|
-
# $6 - to semantic version
|
131
|
-
#
|
132
|
-
MIGRATION_SUB_RE = /(#{RELEASE_SUB_RE})_(#{RELEASE_SUB_RE})/
|
133
|
-
MIGRATION_RE = /^#{MIGRATION_SUB_RE}$/
|
183
|
+
# RELEASE_SUB_RE = /
|
184
|
+
# (?:(#{CUSTOM_NAME_SUB_RE})-)?
|
185
|
+
# (#{MMP_SEMVER_SUB_RE})
|
186
|
+
# /x
|
187
|
+
# RELEASE_RE = /^#{RELEASE_SUB_RE}$/
|
134
188
|
|
135
189
|
# Matches a prerelease branch
|
136
190
|
#
|
@@ -138,11 +192,11 @@ module Prick
|
|
138
192
|
# $1 - custom name, can be nil
|
139
193
|
# $2 - semantic version
|
140
194
|
#
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
195
|
+
# PRERELEASE_SUB_RE = /
|
196
|
+
# (?:(#{CUSTOM_NAME_SUB_RE})-)?
|
197
|
+
# (#{MMP_SEMVER_SUB_RE}-#{PRE_SEMVER_SUB_RE})
|
198
|
+
# /x
|
199
|
+
# PRERELEASE_RE = /^#{PRERELEASE_SUB_RE}$/
|
146
200
|
|
147
201
|
# Matches a feature branch
|
148
202
|
#
|
@@ -151,8 +205,21 @@ module Prick
|
|
151
205
|
# $2 - semantic version
|
152
206
|
# $3 - feature name
|
153
207
|
#
|
154
|
-
|
155
|
-
|
208
|
+
# FEATURE_SUB_RE = /#{ABSTRACT_RELEASE_SUB_RE}_(#{FEATURE_NAME_SUB_RE})/
|
209
|
+
# FEATURE_RE = /^#{FEATURE_SUB_RE}$/
|
210
|
+
|
211
|
+
# Migration RE. The syntax is <version>_<version>
|
212
|
+
#
|
213
|
+
# The RE defines the following captures
|
214
|
+
# $1 - from version
|
215
|
+
# $2 - from custom name, can be nil
|
216
|
+
# $3 - from semantic version
|
217
|
+
# $4 - to version
|
218
|
+
# $5 - to custom name, can be nil
|
219
|
+
# $6 - to semantic version
|
220
|
+
#
|
221
|
+
# MIGRATION_SUB_RE = /(#{RELEASE_SUB_RE})_(#{RELEASE_SUB_RE})/
|
222
|
+
# MIGRATION_RE = /^#{MIGRATION_SUB_RE}$/
|
156
223
|
|
157
224
|
# Project release RE. The general syntax is '<project>-<custom>-<version>'
|
158
225
|
#
|
@@ -195,5 +262,12 @@ module Prick
|
|
195
262
|
ALL_DATABASES_RE = /^#{ALL_DATABASES_SUB_RE}$/
|
196
263
|
def self.all_databases_sub_re(project_name) /(#{project_name})(?:-(#{ABSTRACT_RELEASE_SUB_RE}))?/ end
|
197
264
|
def self.all_databases_re(project_name) /^#{all_databases_sub_re(project_name)}$/ end
|
265
|
+
|
266
|
+
# Matches temporary databases. Mostly useful when debugging because temporary databases
|
267
|
+
# should be deleted on exit
|
268
|
+
TMP_DATABASES_SUB_RE = /#{PROJECT_NAME_SUB_RE}-(?:base|next)/
|
269
|
+
TMP_DATABASES_RE = /^#{TMP_DATABASES_SUB_RE}$/
|
270
|
+
def self.tmp_databases_sub_re(project_name) /#{project_name}-(?:base|next)/ end
|
271
|
+
def self.tmp_databases_re(project_name) /^#{tmp_databases_sub_re(project_name)}$/ end
|
198
272
|
end
|
199
273
|
|
data/lib/prick/database.rb
CHANGED
@@ -1,26 +1,29 @@
|
|
1
1
|
|
2
|
-
require "prick/ensure.rb"
|
3
|
-
|
4
2
|
module Prick
|
5
3
|
class Database
|
6
4
|
attr_reader :name
|
7
5
|
attr_reader :user
|
8
6
|
|
9
7
|
def initialize(name, user)
|
8
|
+
name != "" or raise "Illegal database name"
|
10
9
|
@name = name
|
11
10
|
@user = user
|
12
11
|
@version = nil
|
13
12
|
end
|
14
13
|
|
15
|
-
def version
|
16
|
-
@version
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
def version(cache: true)
|
15
|
+
if cache && @version
|
16
|
+
@version
|
17
|
+
else
|
18
|
+
@version = begin
|
19
|
+
version =
|
20
|
+
if exist? && Rdbms.exist_table?(name, "prick", "versions")
|
21
|
+
Rdbms.select(name, "select version from prick.versions")&.first&.first
|
22
|
+
else
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
version && Version.new(version)
|
26
|
+
end
|
24
27
|
end
|
25
28
|
end
|
26
29
|
|
@@ -42,17 +45,22 @@ module Prick
|
|
42
45
|
def recreate() drop if exist?; create; @version = nil end
|
43
46
|
def drop() Rdbms.drop_database(name, fail: false); @version = nil end
|
44
47
|
|
45
|
-
def loaded?()
|
46
|
-
|
48
|
+
def loaded?() !version.nil? end
|
49
|
+
|
50
|
+
def load(file)
|
51
|
+
!loaded? or raise Internal, "Database #{name} is already loaded"
|
52
|
+
Rdbms.load(name, file, user: user)
|
53
|
+
version # Provoke load of version
|
54
|
+
end
|
47
55
|
|
48
|
-
def save(file)
|
56
|
+
def save(file)
|
57
|
+
loaded? or raise Internal, "Database #{name} is not loaded"
|
58
|
+
Rdbms.save(name, file)
|
59
|
+
@version = nil
|
60
|
+
end
|
49
61
|
|
50
|
-
|
62
|
+
def clean() recreate end # TODO: Find solution that doesn't involve dropping the database
|
51
63
|
|
52
|
-
|
53
|
-
@states = {
|
54
|
-
exist: [:create, :drop],
|
55
|
-
loaded: [:exist, :load, :recreate]
|
56
|
-
}
|
64
|
+
def to_s() name end
|
57
65
|
end
|
58
66
|
end
|
data/lib/prick/diff.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
module Prick
|
2
|
+
class Diff
|
3
|
+
# Diff as a list of lines
|
4
|
+
attr_reader :diff
|
5
|
+
|
6
|
+
# Subject of the diff
|
7
|
+
attr_reader :before_table_changes
|
8
|
+
attr_reader :table_changes
|
9
|
+
attr_reader :after_table_changes
|
10
|
+
|
11
|
+
def initialize(db1, db2)
|
12
|
+
@db1, @db2 = db1, db2
|
13
|
+
do_diff
|
14
|
+
split_on_table_changes
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.same?(db1, db2) Diff.new(db1, db2).same? end
|
18
|
+
|
19
|
+
# Return true if the two databases are equal. Named #same? to avoid name
|
20
|
+
# collision with the built in #equal?
|
21
|
+
def same?() diff.empty? end
|
22
|
+
|
23
|
+
# Write the diff between the databases to the given file(s). Return true if
|
24
|
+
# the databases are equal
|
25
|
+
def write_segments(file1, file2 = nil, file3 = nil, mark: true)
|
26
|
+
if file2.nil? && file3.nil?
|
27
|
+
file2 = file3 = file1
|
28
|
+
elsif file2.nil? ^ !file3.nil?
|
29
|
+
raise Internal, "Either none or both of `file2` and `file3` should be nil"
|
30
|
+
end
|
31
|
+
write_segment(file1, :before_table_changes, mark: mark)
|
32
|
+
write_segment(file2, :table_changes, mark: mark)
|
33
|
+
write_segment(file3, :after_table_changes, mark: mark)
|
34
|
+
end
|
35
|
+
|
36
|
+
def write_segment(file, segment, mark: true)
|
37
|
+
lines = self.send(segment)
|
38
|
+
if lines.empty?
|
39
|
+
FileUtils.rm_f(file) if file != "/dev/stdout"
|
40
|
+
else
|
41
|
+
File.open(file, "w") { |f|
|
42
|
+
f.puts "--" + segment.to_s.gsub("_", " ").upcase if mark
|
43
|
+
f.puts lines
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def do_diff(file = nil)
|
50
|
+
command = "migra --unsafe --with-privileges postgres:///#{@db1} postgres:///#{@db2}"
|
51
|
+
@diff = Command.command(command, fail: false)
|
52
|
+
[0,2].include?(Command.status) or
|
53
|
+
raise Internal, "migrate command failed with status #{Command.status}: #{command}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Initialize table change variables
|
57
|
+
def split_on_table_changes
|
58
|
+
@before_table_changes = []
|
59
|
+
@table_changes = []
|
60
|
+
@after_table_changes = []
|
61
|
+
|
62
|
+
before = true
|
63
|
+
tables = false
|
64
|
+
after = false
|
65
|
+
|
66
|
+
in_table = false
|
67
|
+
|
68
|
+
diff.each { |l|
|
69
|
+
if before
|
70
|
+
if l =~ /^alter table/
|
71
|
+
@table_changes << l
|
72
|
+
before = false
|
73
|
+
tables = true
|
74
|
+
elsif l =~ /^create table/
|
75
|
+
@table_changes << l
|
76
|
+
before = false
|
77
|
+
tables = true
|
78
|
+
in_table = true
|
79
|
+
elsif l =~ /^drop table/
|
80
|
+
@table_changes << l
|
81
|
+
before = false
|
82
|
+
tables = true
|
83
|
+
else
|
84
|
+
@before_table_changes << l
|
85
|
+
end
|
86
|
+
elsif tables
|
87
|
+
if in_table
|
88
|
+
if l =~ /^\)/
|
89
|
+
@table_changes << l
|
90
|
+
in_table = false
|
91
|
+
else
|
92
|
+
@table_changes << l
|
93
|
+
end
|
94
|
+
elsif l =~ /^alter table/
|
95
|
+
@table_changes << l
|
96
|
+
elsif l =~ /^create table/
|
97
|
+
@table_changes << l
|
98
|
+
in_table = true
|
99
|
+
elsif l =~ /^drop table/
|
100
|
+
@table_changes << l
|
101
|
+
elsif l =~ /^\s*$/
|
102
|
+
@table_changes << l
|
103
|
+
else
|
104
|
+
@after_table_changes << l
|
105
|
+
tables = false
|
106
|
+
after = true
|
107
|
+
end
|
108
|
+
else
|
109
|
+
@after_table_changes << l
|
110
|
+
end
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
|