prick 0.17.0 → 0.20.1

Sign up to get free protection for your applications and to get access to all the features.
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 -202
  71. data/lib/prick/cache.rb +0 -34
  72. data/lib/prick/command.rb +0 -93
  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
-