prick 0.18.0 → 0.20.2

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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -4
  3. data/README.md +7 -7
  4. data/Rakefile +3 -1
  5. data/TODO +13 -11
  6. data/bin/console +2 -1
  7. data/doc/build-yml.txt +14 -0
  8. data/exe/prick +264 -28
  9. data/lib/builder/batch.rb +147 -0
  10. data/lib/builder/builder.rb +122 -0
  11. data/lib/builder/node.rb +189 -0
  12. data/lib/builder/node_pool.rb +105 -0
  13. data/lib/builder/parser.rb +120 -0
  14. data/lib/local/command.rb +193 -0
  15. data/lib/{prick → local}/git.rb +148 -22
  16. data/lib/local/timer.rb +98 -0
  17. data/lib/prick/constants.rb +54 -66
  18. data/lib/prick/diff.rb +28 -18
  19. data/lib/prick/prick_version.rb +161 -0
  20. data/lib/prick/state.rb +80 -165
  21. data/lib/prick/version.rb +2 -163
  22. data/lib/prick.rb +43 -27
  23. data/lib/share/init/.gitignore +10 -0
  24. data/lib/share/init/.prick-context +2 -0
  25. data/lib/share/init/.rspec +3 -0
  26. data/{share/schema/schema/public → lib/share/init/migration}/.keep +0 -0
  27. data/lib/share/init/prick.yml +6 -0
  28. data/lib/share/init/schema/.keep +0 -0
  29. data/lib/share/init/schema/build.yml +2 -0
  30. data/lib/share/init/schema/prick/.keep +0 -0
  31. data/lib/share/init/schema/prick/build.yml +5 -0
  32. data/lib/share/init/schema/prick/data.sql +6 -0
  33. data/{share/schema → lib/share/init}/schema/prick/tables.sql +2 -3
  34. data/lib/share/init/schema/public/.keep +0 -0
  35. data/lib/share/init/spec/prick_helper.rb +1 -0
  36. data/lib/share/init/spec/prick_spec.rb +6 -0
  37. data/lib/share/init/spec/spec_helper.rb +50 -0
  38. data/lib/share/migrate/migration/build.yml +4 -0
  39. data/lib/share/migrate/migration/diff.after-tables.sql +0 -0
  40. data/lib/share/migrate/migration/diff.before-tables.sql +0 -0
  41. data/lib/share/migrate/migration/diff.tables.sql +0 -0
  42. data/lib/subcommand/prick-build.rb +55 -0
  43. data/lib/subcommand/prick-create.rb +78 -0
  44. data/lib/subcommand/prick-drop.rb +25 -0
  45. data/lib/subcommand/prick-fox.rb +62 -0
  46. data/lib/subcommand/prick-init.rb +46 -0
  47. data/lib/subcommand/prick-make.rb +202 -0
  48. data/lib/subcommand/prick-migrate.rb +37 -0
  49. data/lib/subcommand/prick-release.rb +23 -0
  50. data/lib/subcommand/prick-setup.rb +20 -0
  51. data/lib/subcommand/prick-teardown.rb +18 -0
  52. data/prick.gemspec +43 -16
  53. metadata +161 -72
  54. data/.gitignore +0 -29
  55. data/.travis.yml +0 -7
  56. data/doc/create_release.txt +0 -17
  57. data/doc/flow.txt +0 -98
  58. data/doc/migra +0 -1
  59. data/doc/migrations.txt +0 -172
  60. data/doc/notes.txt +0 -116
  61. data/doc/prick.txt +0 -114
  62. data/doc/sh.prick +0 -316
  63. data/lib/ext/algorithm.rb +0 -14
  64. data/lib/ext/fileutils.rb +0 -26
  65. data/lib/ext/forward_method.rb +0 -18
  66. data/lib/ext/pg.rb +0 -18
  67. data/lib/ext/shortest_path.rb +0 -44
  68. data/lib/prick/archive.rb +0 -124
  69. data/lib/prick/branch.rb +0 -254
  70. data/lib/prick/builder.rb +0 -205
  71. data/lib/prick/cache.rb +0 -34
  72. data/lib/prick/command.rb +0 -102
  73. data/lib/prick/database.rb +0 -82
  74. data/lib/prick/dsort.rb +0 -151
  75. data/lib/prick/ensure.rb +0 -119
  76. data/lib/prick/exceptions.rb +0 -25
  77. data/lib/prick/head.rb +0 -183
  78. data/lib/prick/migration.rb +0 -70
  79. data/lib/prick/program.rb +0 -506
  80. data/lib/prick/project.rb +0 -626
  81. data/lib/prick/rdbms.rb +0 -137
  82. data/lib/prick/schema.rb +0 -27
  83. data/lib/prick/share.rb +0 -64
  84. data/libexec/strip-comments +0 -33
  85. data/make_releases +0 -72
  86. data/make_schema +0 -10
  87. data/share/diff/diff.after-tables.sql +0 -4
  88. data/share/diff/diff.before-tables.sql +0 -4
  89. data/share/diff/diff.tables.sql +0 -8
  90. data/share/features/diff.sql +0 -2
  91. data/share/features/feature/diff.sql +0 -2
  92. data/share/features/feature/migrate.sql +0 -2
  93. data/share/features/features.sql +0 -2
  94. data/share/features/features.yml +0 -2
  95. data/share/features/migrations.sql +0 -4
  96. data/share/gitignore +0 -2
  97. data/share/migration/diff.tables.sql +0 -8
  98. data/share/migration/features.yml +0 -6
  99. data/share/migration/migrate.sql +0 -3
  100. data/share/migration/migrate.yml +0 -8
  101. data/share/migration/tables.sql +0 -3
  102. data/share/schema/build.yml +0 -14
  103. data/share/schema/schema/build.yml +0 -3
  104. data/share/schema/schema/prick/build.yml +0 -14
  105. data/share/schema/schema/prick/data.sql +0 -7
  106. data/share/schema/schema/prick/schema.sql +0 -3
  107. data/share/schema/schema/public/build.yml +0 -13
  108. data/share/schema/schema.sql +0 -3
  109. data/test_assorted +0 -192
  110. data/test_feature +0 -112
  111. data/test_refactor +0 -34
  112. data/test_single_dev +0 -83
data/lib/prick/dsort.rb DELETED
@@ -1,151 +0,0 @@
1
- require 'tsort'
2
-
3
- module DSort
4
- # Thrown if a cyclic dependency is detected
5
- #
6
- # DSort::Cyclic is inherited from TSort::Cyclic so that recue handling code
7
- # written for TSort will still work. It provides a #cycles member that lists
8
- # the cycles
9
- class Cyclic < TSort::Cyclic
10
- # List of detected cycles sorted from shortest to longest cycle
11
- attr_reader :cycles
12
-
13
- def initialize(dsort_object)
14
- @cycles =
15
- dsort_object.each_strongly_connected_component \
16
- .select { |e| e.size > 1 } \
17
- .sort { |l,r| r <=> l }
18
- gram = cycles.size > 1 ? "ies" : "y"
19
- super("Cyclic depedendenc#{gram} detected")
20
- end
21
- end
22
-
23
- # dsort sorts its input in "dependency" order: The input can be thought of
24
- # depends-on relations between objects and the output as sorted in the order
25
- # needed to safisfy those dependencies so that no object comes before an
26
- # object it depends on
27
- #
28
- # dsort can take an array or a hash argument, or be supplied with a block
29
- #
30
- # The Array argument should consist of pairs (two-element Arrays) with the
31
- # first element being the depending object and the second an object or an
32
- # array of objects it depends on: For example [:a, :b] means that :a depends
33
- # on :b, and [:b, [:c, :d]] that :b depends on both :c and :d
34
- #
35
- # The Hash argument should be a hash from depending object to an object or
36
- # array of objects it depends on. If h is a Hash then dsort(h) is equivalent
37
- # to dsort(h.to_a)
38
- #
39
- # Note that if the elements are arrays themselves, then you should use the
40
- # array form to list the dependencies even if there is only one dependency.
41
- # Ie. use [:a, [:b]] or {:a => [:b] } instead of [:a, :b] or {:a => :b}
42
- #
43
- # If dsort is given a block, the block is given an element as argument and
44
- # should return an (possibly empty) array of the objects the argument depends
45
- # on. The argument to dsort should be an element or an array of elements to
46
- # be given to the block. Note that if the elements are arrays themselves,
47
- # then the arguments to dsort should use the array form even if there is only
48
- # one element. Ie. Use dsort([:a]) instead of dsort(:a)
49
- #
50
- # dsort raise a DSort::Cyclic exception if a cycle detected
51
- #
52
- # Example: If we have that dsort depends on ruby and rspec, ruby depends
53
- # on C to compile, and rspec depends on ruby, then in what order should we
54
- # build them ? Using dsort we could do
55
- #
56
- # p dsort [[:dsort, [:ruby, :rspec]]], [:ruby, :C], [:rspec, :ruby]]
57
- # => [:C, :ruby, :rspec, :dsort]
58
- #
59
- # Using a hash
60
- #
61
- # h = {
62
- # :dsort => [:ruby, :rspec],
63
- # :ruby => [:C],
64
- # :rspec => [:ruby]
65
- # }
66
- # p dsort(h) # Same as dsort(h.to_a)
67
- # => [:C, :ruby, :rspec, :dsort]
68
- #
69
- # or using a block
70
- #
71
- # p dsort(:dsort) { |e| h[e] }
72
- # => [:C, :ruby, :rspec, :dsort]
73
- #
74
- def dsort(a, &block)
75
- sort_object = DSortPrivate::DSortObject.new(a, &block)
76
- begin
77
- sort_object.tsort
78
- rescue TSort::Cyclic
79
- raise Cyclic.new(sort_object)
80
- end
81
- end
82
-
83
- # tsort sort its input in topological order: The input can be thought of as
84
- # comes-before relations between objects and the output will be in
85
- # first-to-last order. This definition corresponds to the mathemacial
86
- # defitionnn of topological sort. See
87
- # http://en.wikipedia.org/wiki/Topological_sorting
88
- #
89
- # Arguments are the same as for dsort. tsort is equivalent to
90
- # dsort(...).reverse
91
- #
92
- # tsort raise a DSort::Cyclic exception if a cycle is detected (DSort::Cyclic
93
- # is an alias for TSort::Cyclic)
94
- #
95
- def tsort(a, &block) dsort(a, &block).reverse end
96
-
97
- module_function :dsort, :tsort
98
-
99
- module DSortPrivate
100
- class DSortObject
101
- include TSort
102
-
103
- # Hash from element to array of dependencies
104
- attr_reader :deps
105
-
106
- # Create @deps hash from object to list of dependencies
107
- def initialize(a, &block)
108
- @deps = {}
109
- if block_given?
110
- a = [a] if !a.is_a?(Array)
111
- a.each { |elem| find_dependencies(elem, &block) }
112
- else
113
- a.each { |obj, deps|
114
- (@deps[obj] ||= []).concat(deps.is_a?(Array) ? deps : [deps])
115
- }
116
- end
117
-
118
- # Make sure all dependent objects are also represented as depending
119
- # objects: If we're given [:a, :b] we want the @deps hash to include
120
- # both :a and :b as keys
121
- @deps.values.each { |deps|
122
- (deps.is_a?(Array) ? deps : [deps]).each { |d|
123
- @deps[d] = [] if !@deps.key?(d)
124
- }
125
- }
126
- end
127
-
128
- # TSort virtual methods
129
- def tsort_each_node(&block) @deps.each_key(&block) end
130
- def tsort_each_child(node, &block) @deps[node].each(&block) end
131
-
132
- private
133
- def find_dependencies(a, &block)
134
- block.call(a).each { |d|
135
- (@deps[a] ||= []) << d
136
- find_dependencies(d, &block)
137
- }
138
- end
139
- end
140
- end
141
- end
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
data/lib/prick/ensure.rb DELETED
@@ -1,119 +0,0 @@
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
-
@@ -1,25 +0,0 @@
1
-
2
- module Prick
3
- class Error < RuntimeError; end
4
- class Fail < Error; end
5
-
6
- class NotYet < NotImplementedError
7
- def initialize() super("Internal error: Not yet implemented") end
8
- end
9
-
10
- class NotThis < ScriptError
11
- def initialize() super("Internal error: Abstract method called") end
12
- end
13
-
14
- class Abstract < ScriptError
15
- def initialize() super("Internal error: Abstract method called") end
16
- end
17
-
18
- AbstractMethod = Abstract
19
-
20
- class Internal < ScriptError; end
21
- class Oops < Internal
22
- def initialize() super("Oops, this shouldn't happen") end
23
- end
24
- end
25
-
data/lib/prick/head.rb DELETED
@@ -1,183 +0,0 @@
1
-
2
- module Prick
3
- class Head
4
- def project_name() Prick.project.name end
5
-
6
- # Usually equal to #version.to_s
7
- attr_reader :name
8
-
9
- # Version. This should be equal to schema.version
10
- attr_reader :version
11
-
12
- def base_version() @migration.base_version end
13
-
14
- attr_reader :schema
15
-
16
- attr_reader :migration
17
-
18
- def clean?() Git::clean? end
19
-
20
- def tag?() false end
21
- def release_tag?() false end
22
- def migration_tag?() false end
23
-
24
- def branch?() false end
25
- def release_branch?() false end
26
- def prerelease_branch?() false end
27
- def feature_branch?() false end
28
- def migration_branch?() false end
29
-
30
- def initialize(name, version, migration)
31
- @name = name
32
- @version = version
33
- @schema = Schema.new
34
- @migration = migration
35
- end
36
-
37
- # TODO: Handle migrations
38
- def self.load(name)
39
- version, tag = Version.parse(name)
40
- if tag
41
- ReleaseTag.load
42
- else
43
- if version.release?
44
- ReleaseBranch.load
45
- elsif version.prerelease?
46
- PrereleaseBranch.load(version)
47
- elsif version.feature?
48
- FeatureBranch.load(version)
49
- else
50
- raise NotHere
51
- end
52
- end
53
- end
54
-
55
- def create()
56
- raise NotThis
57
- end
58
-
59
- def build(database)
60
- schema.build(database)
61
- end
62
-
63
- def self.database_name(version)
64
- version.truncate(:pre).to_s
65
- end
66
- end
67
-
68
- class Tag < Head
69
- def tag?() true end
70
-
71
- def initialize(version, base_version, migration = nil)
72
- migration ||= Migration.new(version, base_version)
73
- super(version.to_s, version, migration)
74
- end
75
-
76
- def self.load
77
- state = Migration.load
78
- self.new(state.version, state.base_version)
79
- end
80
-
81
- def create
82
- initial_branch_name = "#{version}_initial"
83
- clean? or raise Internal, "Repository is not clean"
84
- !Git.detached? or raise Internal, "Not on a branch"
85
- Git.create_branch(initial_branch_name)
86
- Git.checkout_branch(initial_branch_name)
87
- migration.update(version)
88
- schema.version = version
89
- Git.commit "Created release v#{version}"
90
- Git.create_tag(version)
91
- Git.checkout_tag(version)
92
- self
93
- end
94
- end
95
-
96
- class ReleaseTag < Tag
97
- def release_tag?() true end
98
- end
99
-
100
- # TODO
101
- class PrereleaseTag < Tag
102
- end
103
-
104
- class MigrationTag < Tag
105
- def migration_tag?() true end
106
- end
107
-
108
- class Branch < Head
109
- def branch?() true end
110
-
111
- def initialize(name, version, migration)
112
- super(name, version, migration)
113
- end
114
-
115
- def create()
116
- Git.create_branch(version)
117
- Git.checkout_branch(version)
118
- migration.create
119
- self
120
- end
121
- end
122
-
123
- class ReleaseBranch < Branch
124
- def release_branch?() true end
125
-
126
- def initialize(fork = nil, base_version)
127
- if fork
128
- version = Version.new(base_version, fork: fork)
129
- else
130
- version = base_version
131
- end
132
- super(version.to_s, version, Migration.new(nil, base_version))
133
- end
134
-
135
- def self.load
136
- state = MigrationState.load
137
- ReleaseBranch.new(nil, state.base_version)
138
- end
139
- end
140
-
141
- class PrereleaseBranch < Branch
142
- def prerelease_branch?() true end
143
-
144
- def initialize(version, base_version)
145
- target_version = version.truncate(:pre)
146
- super(version.to_s, target_version, Migration.new(target_version, base_version))
147
- end
148
-
149
- def self.load
150
- state = MigrationState.load
151
- PrereleaseBranch.new(state.version, state.base_version)
152
- end
153
- end
154
-
155
- class FeatureBranch < Branch
156
- def feature_branch?() true end
157
-
158
- def initialize(feature_name, base_version)
159
- name = Version.new(base_version, feature: feature_name).to_s
160
- super(name, base_version, FeatureMigration.new(feature_name, base_version))
161
- end
162
-
163
- def self.load
164
- state = MigrationState.load
165
- FeatureBranch.new(state.version.feature)
166
- end
167
- end
168
-
169
- # TODO: Versioned migrations (or maybe not)
170
- class MigrationBranch < Branch
171
- def migrationn_branch?() true end
172
-
173
- def initialize(version, base_version)
174
- if (version.fork || "") == (base_version.fork || "")
175
- name = version.to_s + "-" + base_version.semver.to_s
176
- else
177
- name = version.to_s + "-" + base_version.to_s
178
- end
179
- super(name, version, Migration.new(version, base_version))
180
- end
181
- end
182
- end
183
-
@@ -1,70 +0,0 @@
1
-
2
- module Prick
3
- class Migration
4
- attr_reader :version
5
- attr_reader :base_version
6
-
7
- def initialize(version, base_version)
8
- @version = version
9
- @base_version = base_version
10
- end
11
-
12
- def self.load
13
- state = MigrationState.load
14
- Migration.new(state.version, state.base_version)
15
- end
16
-
17
- # Remove content of the migration/ directory
18
- def self.clear
19
- FileUtils.empty!(MIGRATION_DIR)
20
- end
21
-
22
- def exist?() MigrationState.exist? end
23
-
24
- def create()
25
- files = Share.cp "migration/*", MIGRATION_DIR
26
- state = MigrationState.new.write(version: version, base_version: base_version)
27
- Git.add files, state.path
28
- self
29
- end
30
-
31
- def update(version)
32
- state = MigrationState.new.read
33
- @version = state.version = version
34
- state.write
35
- Git.add state.path
36
- self
37
- end
38
-
39
- def migrate(database)
40
- base_version or raise Internal, "Can't migrate from nil to #{version}"
41
- version or raise Internal, "Can't migrate from #{base_version} to nil"
42
- MigrationBuilder.new(database, MIGRATION_DIR).build
43
- end
44
- end
45
-
46
- class FeatureMigration < Migration
47
- attr_reader :feature
48
-
49
- def initialize(feature, base_version)
50
- super(base_version, base_version)
51
- @feature = feature
52
- end
53
-
54
- def self.load
55
- migration_state = MigrationState.load
56
- feature_state = FeatureState.load
57
- FeatureMigration.new(feature_state.feature, migration_state.base_version)
58
- end
59
-
60
- def create()
61
- super
62
- files = Share.cp "migration", File.join(MIGRATION_DIR, feature)
63
- state = FeatureState.write(feature: feature)
64
- Git.add files, state.path
65
- self
66
- end
67
- end
68
- end
69
-
70
-