prick 0.2.0 → 0.7.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/.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
|
+
|