prick 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 +7 -0
- data/.gitignore +28 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/README.md +35 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/doc/create_release.txt +17 -0
- data/doc/flow.txt +98 -0
- data/doc/migra +1 -0
- data/doc/migrations.txt +172 -0
- data/doc/notes.txt +116 -0
- data/doc/sh.prick +316 -0
- data/exe/prick +467 -0
- data/file +0 -0
- data/lib/ext/algorithm.rb +14 -0
- data/lib/ext/fileutils.rb +8 -0
- data/lib/ext/pg.rb +18 -0
- data/lib/prick.rb +21 -0
- data/lib/prick/archive.rb +124 -0
- data/lib/prick/build.rb +376 -0
- data/lib/prick/command.rb +85 -0
- data/lib/prick/constants.rb +199 -0
- data/lib/prick/database.rb +58 -0
- data/lib/prick/dsort.rb +151 -0
- data/lib/prick/ensure.rb +119 -0
- data/lib/prick/exceptions.rb +13 -0
- data/lib/prick/git.rb +159 -0
- data/lib/prick/migra.rb +22 -0
- data/lib/prick/migration.rb +230 -0
- data/lib/prick/project.rb +444 -0
- data/lib/prick/rdbms.rb +147 -0
- data/lib/prick/schema.rb +100 -0
- data/lib/prick/version.rb +133 -0
- data/make_releases +369 -0
- data/prick.gemspec +46 -0
- data/share/features/diff.sql +2 -0
- data/share/features/feature/diff.sql +2 -0
- data/share/features/feature/migrate.sql +2 -0
- data/share/features/features.sql +2 -0
- data/share/features/features.yml +2 -0
- data/share/features/migrations.sql +4 -0
- data/share/gitignore +2 -0
- data/share/schemas/prick/data.sql +8 -0
- data/share/schemas/prick/schema.sql +20 -0
- metadata +188 -0
data/lib/prick/ensure.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
module Prick
|
2
|
+
# Example:
|
3
|
+
#
|
4
|
+
# class Some
|
5
|
+
# include Ensure
|
6
|
+
#
|
7
|
+
# def exist?() ... end
|
8
|
+
# def create() ... end
|
9
|
+
# def destroy() ... end
|
10
|
+
#
|
11
|
+
# def loaded?() ... end
|
12
|
+
# def load() ... end
|
13
|
+
# def unload() ... end
|
14
|
+
#
|
15
|
+
# @ensure_states = {
|
16
|
+
# exist: [:create, :destroy],
|
17
|
+
# loaded: [:exist, :load, :unload] # Depends on :exist
|
18
|
+
# }
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# some = Some.new
|
22
|
+
# some.ensure_state(:loaded) # -> calls #create and then #load
|
23
|
+
# some.revoke_state(:loaded) # -> calls #unload but not #destroy
|
24
|
+
# some.ensure_state_value(:exist, false) # same as #revoke_state(:exist)
|
25
|
+
#
|
26
|
+
module Ensure
|
27
|
+
def ensure_state(state, *args) ensure_state_value(state, true, *args) end
|
28
|
+
def revoke_state(state, *args) ensure_state_value(state, false, *args) end
|
29
|
+
def ensure_state_value(state, value, *args) EnsureMethods.ensure(self, state, value, *args) end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Helper module
|
33
|
+
module EnsureMethods
|
34
|
+
def self.klass(module_or_object)
|
35
|
+
module_or_object.is_a?(Module) ? module_or_object : module_or_object.class
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.all_included(m)
|
39
|
+
m.singleton_class.included_modules
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.all_extended(c)
|
43
|
+
c.ancestors
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.all_states(c)
|
47
|
+
h = {}
|
48
|
+
(all_extended(c) + all_included(c)).reverse.each { |klass|
|
49
|
+
h.merge!(klass.instance_variable_get("@ensure_states") || {})
|
50
|
+
}
|
51
|
+
h
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.ensure(module_or_object, state, expected, *args)
|
55
|
+
# module_or_object_text = module_or_object.is_a?(Module) ? "<module>" : "<object>"
|
56
|
+
# puts "ensure_state_impl(#{module_or_object_text.inspect}, #{state.inspect}, #{expected}, #{args.inspect})"
|
57
|
+
|
58
|
+
object = module_or_object
|
59
|
+
klass = self.klass(module_or_object)
|
60
|
+
value = call_method(object, :"#{state}?", *args)
|
61
|
+
|
62
|
+
if value != expected
|
63
|
+
entry = all_states(klass)[state] or
|
64
|
+
raise Prick::Error, "Can't find state #{state.inspect}"
|
65
|
+
|
66
|
+
# Handle ensure-pre-conditions recursively
|
67
|
+
precondition = (entry.size == 3 ? entry.shift : nil)
|
68
|
+
entry.size == 2 or raise "Malformed state entry for #{state.inspect}"
|
69
|
+
if precondition && expected # Don't tear down recursively
|
70
|
+
case precondition
|
71
|
+
when Symbol
|
72
|
+
self.ensure(object, precondition, true, *args)
|
73
|
+
when Proc
|
74
|
+
call_method(object, precondition, *args)
|
75
|
+
else
|
76
|
+
raise Prick::Fail, "Unexpected value: #{precondition.inspect}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
method = entry[expected ? 0 : 1]
|
81
|
+
case method
|
82
|
+
when true # a noop
|
83
|
+
;
|
84
|
+
when false # an error
|
85
|
+
relation = (expected ? "to" : "from")
|
86
|
+
raise Error, "Can't change state #{relation} #{state.inspect}"
|
87
|
+
when Symbol # a method
|
88
|
+
call_method(object, method, *args)
|
89
|
+
when Proc # a lambda
|
90
|
+
call_method(object, method, *args)
|
91
|
+
else
|
92
|
+
raise Error, "Illegal @states entry: #{method.inspect}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
self # so that you can do 'some = Some.new.ensure_state(:loaded)' in one go
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.vargs(arity, args)
|
99
|
+
n_args = (arity < 0 ? -(1 + arity) : arity)
|
100
|
+
args[0...n_args]
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.call_method(object, symbol_or_lambda, *args)
|
104
|
+
# sol_text = symbol_or_lambda.is_a?(Proc) ? "<Proc>" : symbol_or_lambda
|
105
|
+
# puts "call_method(#{object.name}, #{sol_text.inspect}, #{args})"
|
106
|
+
|
107
|
+
if symbol_or_lambda.is_a?(Symbol)
|
108
|
+
executor = object.method(symbol_or_lambda)
|
109
|
+
executor.call(*vargs(executor.arity, args))
|
110
|
+
elsif symbol_or_lambda.is_a?(Proc)
|
111
|
+
executor = symbol_or_lambda
|
112
|
+
executor.call(object, *vargs(executor.arity, args))
|
113
|
+
else
|
114
|
+
raise Prick::Fail, "Illegal value: #{symbol_or_lambda.inspect}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
module Prick
|
3
|
+
class Error < RuntimeError; end
|
4
|
+
class Fail < Error; end
|
5
|
+
class NotYet < NotImplementedError
|
6
|
+
def initialize() super("Program error - Not yet implemented") end
|
7
|
+
end
|
8
|
+
class AbstractMethod < ScriptError
|
9
|
+
def initialize() super("Program error - Abstract method called") end
|
10
|
+
end
|
11
|
+
class Internal < ScriptError; end
|
12
|
+
end
|
13
|
+
|
data/lib/prick/git.rb
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
|
2
|
+
require "prick/command.rb"
|
3
|
+
|
4
|
+
module Prick
|
5
|
+
# Tags have a 'v' prefixed the version in the git repository but this is made
|
6
|
+
# transparent to the application
|
7
|
+
module Git
|
8
|
+
def self.init
|
9
|
+
Command.command "git init"
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns true if the repository has no modified files. Requires the
|
13
|
+
# repository to have at least one commit. Creating the repository using
|
14
|
+
# Project::initialize_directory guarantees that
|
15
|
+
def self.clean?()
|
16
|
+
Command.command("git status").find { |l|
|
17
|
+
l =~ /Changes to be committed:/ || l =~ /^\s*modified:/
|
18
|
+
}.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns true if the repository is on a detached branch
|
22
|
+
def self.detached?
|
23
|
+
line = File.readlines(".git/HEAD").first.chomp
|
24
|
+
line =~ /^ref:/ ? false : true
|
25
|
+
end
|
26
|
+
|
27
|
+
# The current tag. This is only defined if the repository is in "detached
|
28
|
+
# head" mode
|
29
|
+
def self.current_tag() raise "Not yet implemented" end
|
30
|
+
|
31
|
+
# Return true if `version` has an associated tag
|
32
|
+
def self.tag?(version)
|
33
|
+
!list_tags.grep(version).empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
# List tag versions
|
37
|
+
# Create version tag
|
38
|
+
def self.create_tag(version)
|
39
|
+
Command.command "git tag -a 'v#{version}' -m 'Release #{version}'"
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.delete_tag(version, remote: false)
|
43
|
+
Command.command "git tag -d 'v#{version}'", fail: false
|
44
|
+
Command.command("git push --delete origin 'v#{version}'", fail: false) if remote
|
45
|
+
end
|
46
|
+
|
47
|
+
# Checkout a version tag as a detached head
|
48
|
+
def self.checkout_tag(version)
|
49
|
+
Command.command "git checkout 'v#{version}'"
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.list_tags
|
53
|
+
Command.command("git tag").map { |tag| tag.sub(/^v(#{VERSION_SUB_RE})/, '\1') }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Name of the current branch
|
57
|
+
def self.current_branch()
|
58
|
+
Command.command("git rev-parse --abbrev-ref HEAD").first
|
59
|
+
end
|
60
|
+
|
61
|
+
# Check if branch exist
|
62
|
+
def self.branch?(name)
|
63
|
+
Command.command("git show-ref --verify --quiet 'refs/heads/#{name}'", fail: false)
|
64
|
+
Command.status == 0
|
65
|
+
end
|
66
|
+
|
67
|
+
# Create a branch
|
68
|
+
def self.create_branch(name)
|
69
|
+
Command.command "git branch #{name}"
|
70
|
+
end
|
71
|
+
|
72
|
+
# Destroy branch
|
73
|
+
def self.delete_branch(name)
|
74
|
+
Command.command "git branch -D #{name}", fail: false
|
75
|
+
end
|
76
|
+
|
77
|
+
# Check out branch
|
78
|
+
def self.checkout_branch(name, create: false)
|
79
|
+
if create
|
80
|
+
Command.command "git checkout -b #{name}"
|
81
|
+
else
|
82
|
+
Command.command "git checkout #{name}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Merge a branch
|
87
|
+
def self.merge_branch(name, exclude_files: [], fail: false)
|
88
|
+
# Save content of excluded files
|
89
|
+
files = {}
|
90
|
+
exclude_files.each { |file|
|
91
|
+
next if !File.exist?(file)
|
92
|
+
files[file] = File.readlines(file)
|
93
|
+
}
|
94
|
+
|
95
|
+
Command.command "git merge --no-commit #{name}", fail: false
|
96
|
+
|
97
|
+
# Reinstate included files
|
98
|
+
files.each { |path, content|
|
99
|
+
File.open(path, "w") { |file| file.puts(content) }
|
100
|
+
# Resolve git unmerged status
|
101
|
+
Git.add(path)
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
# List branches
|
106
|
+
def self.list_branches
|
107
|
+
Command.command "git branch --format='%(refname:short)'"
|
108
|
+
end
|
109
|
+
|
110
|
+
# Add a file to the index of the current branch
|
111
|
+
def self.add(*files)
|
112
|
+
Array(files).each { |file|
|
113
|
+
Dir.chdir(File.dirname(file)) {
|
114
|
+
Command.command "git add '#{File.basename(file)}'"
|
115
|
+
}
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
# Return content of file in the given tag or branch. Defaults to HEAD
|
120
|
+
def self.readlines(file, tag: nil, branch: nil)
|
121
|
+
!(tag && branch) or raise Internal, "Can't use both tag: and branch: options"
|
122
|
+
if tag
|
123
|
+
Command.command "git show v#{tag}:#{file}"
|
124
|
+
else
|
125
|
+
branch ||= "HEAD"
|
126
|
+
Command.command "git show #{branch}:#{file}"
|
127
|
+
end.map { |l| "#{l}\n" }
|
128
|
+
end
|
129
|
+
|
130
|
+
# Return content of file
|
131
|
+
def self.read(file, tag: nil, branch: nil)
|
132
|
+
!(tag && branch) or raise Internal, "Can't use both tag: and branch: options"
|
133
|
+
if tag
|
134
|
+
Command.command "git show v#{tag}:#{file}"
|
135
|
+
else
|
136
|
+
branch ||= "HEAD"
|
137
|
+
Command.command "git show #{branch}:#{file}"
|
138
|
+
end.join("\n")
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.rm(file)
|
142
|
+
Dir.chdir(File.dirname(file)) {
|
143
|
+
Command.command "git rm -f '#{File.basename(file)}'", fail: false
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.rm_rf(file)
|
148
|
+
Dir.chdir(File.dirname(file)) {
|
149
|
+
Command.command "git rm -rf '#{File.basename(file)}'", fail: false
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
# Commit changes on the current branch"
|
154
|
+
def self.commit(msg)
|
155
|
+
Command.command "git commit -m '#{msg}'"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
data/lib/prick/migra.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
module Prick
|
3
|
+
module Migra
|
4
|
+
def self.migrate(from_name, to_name, file)
|
5
|
+
args = urls(from_name, to_name).join(" ")
|
6
|
+
options = OPTIONS.join(" ")
|
7
|
+
Command.command %(
|
8
|
+
status=0
|
9
|
+
migra #{options} #{args} >#{file} || { status=$?; }
|
10
|
+
[ $status = 2 ] || exit 1
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
OPTIONS = %w(--unsafe --with-privileges)
|
16
|
+
|
17
|
+
def self.urls(*args)
|
18
|
+
args = Array(args).flatten
|
19
|
+
args.map { |name| "postgresql:///#{name}" }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Prick
|
5
|
+
class Migration
|
6
|
+
KEEP_FILE = ".keep"
|
7
|
+
|
8
|
+
attr_reader :path
|
9
|
+
|
10
|
+
def files() raise AbstractMethod end
|
11
|
+
def release_files() files end
|
12
|
+
|
13
|
+
# Return versions of the features in this migration
|
14
|
+
def feature_versions() raise AbstractMethod end
|
15
|
+
|
16
|
+
def initialize(path, template_dir)
|
17
|
+
@path = path
|
18
|
+
@template_dir = template_dir
|
19
|
+
end
|
20
|
+
|
21
|
+
def exist?() File.exist?(keep_file) end
|
22
|
+
def create() FileUtils.touch_p(keep_file); Git.add(keep_file) end
|
23
|
+
def destroy() Git.rm_rf(path) end
|
24
|
+
|
25
|
+
def present?() exist? && files.all? { |f| File.exist?(f) } end
|
26
|
+
def prepare() files.each { |f| FileUtils.cp(template_file(f), path) }; Git.add(path) end
|
27
|
+
|
28
|
+
def include_feature(feature) raise AbstractMethod end
|
29
|
+
|
30
|
+
def migrate() raise AbstractMethod end
|
31
|
+
|
32
|
+
def to_s() path end
|
33
|
+
def <=>(other) path <=> other.path end
|
34
|
+
|
35
|
+
def self.path(version)
|
36
|
+
if version.feature?
|
37
|
+
File.join(FEATURE_DIR, version.truncate(:feature).to_s, version.feature)
|
38
|
+
else
|
39
|
+
File.join(FEATURE_DIR, version)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.version(path)
|
44
|
+
Version.new(path.delete_prefix("#{FEATURE_DIR}/").sub("/", "_"))
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.feature?(path)
|
48
|
+
Version.new(path.delete_prefix("#{FEATURE_DIR}/").sub("/", "_")).feature?
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.files(path) raise AbstractMethod end
|
52
|
+
def self.release_files(path) files(path) end
|
53
|
+
|
54
|
+
def dump(&block)
|
55
|
+
# puts self.class
|
56
|
+
# indent {
|
57
|
+
# puts "path : #{path}"
|
58
|
+
# puts "files: #{files.inspect}"
|
59
|
+
# puts "release_files: #{release_files.inspect}"
|
60
|
+
# puts "feature_versions: #{feature_versions.map(&:to_s).inspect}"
|
61
|
+
# puts "keep_file: #{keep_file}"
|
62
|
+
# yield if block_given?
|
63
|
+
# }
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
def template_file(path) File.join(SHARE_PATH, @template_dir, File.basename(path)) end
|
68
|
+
def keep_file() File.join(path, KEEP_FILE) end
|
69
|
+
end
|
70
|
+
|
71
|
+
class ReleaseMigration < Migration
|
72
|
+
FEATURES_TMPL_DIR = "features"
|
73
|
+
FILES = [
|
74
|
+
FEATURES_SQL = "features.sql",
|
75
|
+
FEATURES_YML = "features.yml",
|
76
|
+
MIGRATIONS_SQL = "migrations.sql",
|
77
|
+
DIFF_SQL = "diff.sql"
|
78
|
+
]
|
79
|
+
|
80
|
+
attr_reader :features_yml
|
81
|
+
attr_reader :features_sql
|
82
|
+
attr_reader :migrations_sql
|
83
|
+
attr_reader :diff_sql
|
84
|
+
|
85
|
+
def files() [features_yml, features_sql, migrations_sql, diff_sql] end
|
86
|
+
|
87
|
+
def initialize(path)
|
88
|
+
super(path, FEATURES_TMPL_DIR)
|
89
|
+
@features_yml = File.join(path, FEATURES_YML)
|
90
|
+
@features_sql = File.join(path, FEATURES_SQL)
|
91
|
+
@migrations_sql = File.join(path, MIGRATIONS_SQL)
|
92
|
+
@diff_sql = File.join(path, DIFF_SQL)
|
93
|
+
end
|
94
|
+
|
95
|
+
def feature_versions() read_features_yml.map { |path| Migration.version(path) } end
|
96
|
+
def feature_paths() read_features_yml end
|
97
|
+
|
98
|
+
# `feature` is a Feature object
|
99
|
+
def include_feature(migration, append: true)
|
100
|
+
migration.is_a?(FeatureMigration) or raise "Expected FeatureMigration object, got #{migration.class}"
|
101
|
+
!feature_paths.include?(migration.path) or raise Error, "Feature #{migration.version} is already included"
|
102
|
+
exclude_files = [Schema.data_file] +
|
103
|
+
migration.release_files +
|
104
|
+
migration.feature_paths.map { |path| FeatureMigration.release_files(path) }.flatten
|
105
|
+
|
106
|
+
Git.merge_branch(migration.version, exclude_files: exclude_files)
|
107
|
+
|
108
|
+
feature_paths = YAML.load(Git.read(migration.features_yml, branch: migration.version))
|
109
|
+
append_features_yml(feature_paths, append: append)
|
110
|
+
|
111
|
+
feature_paths.each { |feature_path|
|
112
|
+
if path != File.dirname(feature_path)
|
113
|
+
FileUtils.ln_s(File.join("../..", feature_path), path)
|
114
|
+
Git.add(File.join(path, File.basename(feature_path)))
|
115
|
+
end
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
def migrate(database_name)
|
120
|
+
puts "ReleaseMigration#migrate"
|
121
|
+
if File.exist?(migrations_sql)
|
122
|
+
Dir.chdir(path) {
|
123
|
+
puts " cd #{path}"
|
124
|
+
puts " psql -d #{database_name} < #{MIGRATIONS_SQL}"
|
125
|
+
Command.command "psql -d #{database_name} < #{MIGRATIONS_SQL}"
|
126
|
+
}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def self.files(path)
|
132
|
+
FILES.map { |file| File.join(path, file) }
|
133
|
+
end
|
134
|
+
|
135
|
+
def read_features_yml(branch = nil) YAML.load(File.read(features_yml)) || [] end
|
136
|
+
|
137
|
+
def append_features_yml(paths, append: true)
|
138
|
+
write_features_yml(read_features_yml.insert(append ? -1 : 0, *paths))
|
139
|
+
end
|
140
|
+
|
141
|
+
def write_features_yml(paths)
|
142
|
+
FileUtils.cp(template_file(features_yml), features_yml)
|
143
|
+
File.open(features_yml, "a") { |f| f.write(paths.to_yaml) }
|
144
|
+
FileUtils.cp(template_file(features_sql), features_sql)
|
145
|
+
File.open(features_sql, "a") { |f|
|
146
|
+
paths.map { |path|
|
147
|
+
f.puts "\\cd #{File.basename(path)}"
|
148
|
+
f.puts "\\i migrate.sql" }
|
149
|
+
f.puts "\\cd .."
|
150
|
+
f.puts
|
151
|
+
}
|
152
|
+
Git.add(features_yml)
|
153
|
+
Git.add(features_sql)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class FeatureMigration < Migration
|
158
|
+
FEATURE_TMPL_DIR = "features/feature"
|
159
|
+
FILES = [
|
160
|
+
MIGRATE_SQL = "migrate.sql",
|
161
|
+
DIFF_SQL = "diff.sql"
|
162
|
+
]
|
163
|
+
|
164
|
+
attr_reader :name
|
165
|
+
attr_reader :version
|
166
|
+
attr_reader :release_migration # The enclosing release migration
|
167
|
+
|
168
|
+
attr_reader :migrate_sql
|
169
|
+
attr_reader :diff_sql
|
170
|
+
|
171
|
+
def features_yml() release_migration.features_yml end
|
172
|
+
def features_sql() release_migration.features_sql end
|
173
|
+
def migrations_sql() release_migration.migrations_sql end
|
174
|
+
def release_diff_sql() release_migration.diff_sql end
|
175
|
+
|
176
|
+
def files() [migrate_sql, diff_sql] end
|
177
|
+
def release_files() release_migration.files end
|
178
|
+
|
179
|
+
def feature_versions() release_migration.feature_versions end
|
180
|
+
def feature_paths() release_migration.feature_paths end
|
181
|
+
|
182
|
+
def initialize(path, name: File.basename(path))
|
183
|
+
Migration.feature?(path) or raise "Expected a feature path, got #{path}"
|
184
|
+
super(path, FEATURE_TMPL_DIR)
|
185
|
+
@name = name
|
186
|
+
@version = Migration.version(path)
|
187
|
+
@release_migration = ReleaseMigration.new(File.dirname(path))
|
188
|
+
@migrate_sql = File.join(path, MIGRATE_SQL)
|
189
|
+
@diff_sql = File.join(path, DIFF_SQL)
|
190
|
+
end
|
191
|
+
|
192
|
+
def exist?() release_migration.exist? && super end
|
193
|
+
def create()
|
194
|
+
release_migration.exist? || release_migration.create
|
195
|
+
super
|
196
|
+
end
|
197
|
+
|
198
|
+
def present?() release_migration.present? && super end
|
199
|
+
def prepare()
|
200
|
+
release_migration.present? || release_migration.prepare
|
201
|
+
super
|
202
|
+
release_migration.append_features_yml([path])
|
203
|
+
end
|
204
|
+
|
205
|
+
def include_feature(migration)
|
206
|
+
release_migration.include_feature(migration, append: false)
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.files(path)
|
210
|
+
release_files + FILES.map { |file| File.join(path, file) }
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.release_files(path)
|
214
|
+
ReleaseMigration.files(path)
|
215
|
+
end
|
216
|
+
|
217
|
+
def dump
|
218
|
+
super {
|
219
|
+
puts "name: #{name}"
|
220
|
+
puts "release_migration: #{path}"
|
221
|
+
}
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
|
228
|
+
|
229
|
+
|
230
|
+
|