shaf 0.4.1 → 0.5.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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data/lib/shaf/command/base.rb +51 -0
- data/lib/shaf/command/templates/Gemfile.erb +0 -1
- data/lib/shaf/command.rb +1 -47
- data/lib/shaf/extensions/resource_uris.rb +113 -151
- data/lib/shaf/generator/base.rb +61 -0
- data/lib/shaf/generator/migration/base.rb +133 -0
- data/lib/shaf/generator/migration/create_table.rb +4 -4
- data/lib/shaf/generator/migration.rb +1 -111
- data/lib/shaf/generator/serializer.rb +3 -51
- data/lib/shaf/generator/templates/api/controller.rb.erb +2 -0
- data/lib/shaf/generator/templates/api/policy.rb.erb +3 -2
- data/lib/shaf/generator/templates/api/serializer.rb.erb +2 -6
- data/lib/shaf/generator/templates/spec/integration_spec.rb.erb +30 -30
- data/lib/shaf/generator.rb +1 -57
- data/lib/shaf/helpers/cache_control.rb +21 -0
- data/lib/shaf/helpers.rb +4 -2
- data/lib/shaf/rake/db.rb +1 -1
- data/lib/shaf/upgrade/manifest.rb +29 -8
- data/lib/shaf/upgrade/package.rb +51 -27
- data/lib/shaf/version.rb +1 -1
- data/templates/api/controllers/docs_controller.rb +2 -0
- data/templates/api/controllers/root_controller.rb +2 -3
- data/templates/api/policies/base_policy.rb +3 -0
- data/templates/api/serializers/base_serializer.rb +4 -0
- data/templates/api/serializers/error_serializer.rb +3 -2
- data/templates/api/serializers/form_serializer.rb +2 -2
- data/templates/api/serializers/root_serializer.rb +3 -3
- data/templates/config/initializers/db_migrations.rb +24 -11
- data/templates/config/initializers/hal_presenter.rb +0 -5
- data/templates/config/settings.yml +8 -3
- data/upgrades/0.5.0.tar.gz +0 -0
- data.tar.gz.sig +0 -0
- metadata +69 -6
- metadata.gz.sig +0 -0
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'date'
|
2
|
-
|
3
1
|
module Shaf
|
4
2
|
module Generator
|
5
3
|
module Migration
|
@@ -20,119 +18,11 @@ module Shaf
|
|
20
18
|
raise Command::ArgumentError, e.message
|
21
19
|
end
|
22
20
|
end
|
23
|
-
|
24
|
-
class Base
|
25
|
-
DB_COL_TYPES = {
|
26
|
-
integer: ['Integer :%s', 'add_column :%s, Integer'],
|
27
|
-
varchar: ['String %s', 'add_column :%s, String'],
|
28
|
-
string: ['String :%s', 'add_column :%s, String'],
|
29
|
-
text: ['String :%s, text: true', 'add_column :%s, String, text: true'],
|
30
|
-
blob: ['File :%s', 'add_column :%s, File'],
|
31
|
-
bigint: ['Bignum :%s', 'add_column :%s, Bignum'],
|
32
|
-
double: ['Float :%s', 'add_column :%s, Float'],
|
33
|
-
numeric: ['BigDecimal :%s', 'add_column :%s, BigDecimal'],
|
34
|
-
date: ['Date :%s', 'add_column :%s, Date'],
|
35
|
-
timestamp: ['DateTime :%s', 'add_column :%s, DateTime'],
|
36
|
-
time: ['Time :%s', 'add_column :%s, Time'],
|
37
|
-
bool: ['TrueClass :%s', 'add_column :%s, TrueClass'],
|
38
|
-
boolean: ['TrueClass :%s', 'add_column :%s, TrueClass'],
|
39
|
-
index: ['index :%s, unique: true', 'add_index :%s'],
|
40
|
-
}
|
41
|
-
|
42
|
-
REGEXP_DB_TYPES = {
|
43
|
-
/\Aforeign_key\((\w+)\)/ => ['foreign_key :%s, :\1', 'add_foreign_key :%s, :\1'],
|
44
|
-
}
|
45
|
-
|
46
|
-
attr_reader :args
|
47
|
-
|
48
|
-
class << self
|
49
|
-
def inherited(child)
|
50
|
-
Factory.register(child)
|
51
|
-
end
|
52
|
-
|
53
|
-
def identifier(*ids)
|
54
|
-
@identifiers = ids.flatten.map(&:to_s)
|
55
|
-
end
|
56
|
-
|
57
|
-
def usage(str = nil, &block)
|
58
|
-
@usage = str || block
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def initialize(*args)
|
63
|
-
@args = args.dup
|
64
|
-
end
|
65
|
-
|
66
|
-
def call
|
67
|
-
validate_args
|
68
|
-
name = compile_migration_name
|
69
|
-
compile_changes
|
70
|
-
[target(name), render]
|
71
|
-
rescue StandardError => e
|
72
|
-
raise Command::ArgumentError, e.message
|
73
|
-
end
|
74
|
-
|
75
|
-
def add_change(change)
|
76
|
-
@changes ||= []
|
77
|
-
@changes << change if change
|
78
|
-
end
|
79
|
-
|
80
|
-
def db_type(type)
|
81
|
-
type ||= :string
|
82
|
-
result = DB_COL_TYPES[type.to_sym]
|
83
|
-
result ||= REGEXP_DB_TYPES.each do |pattern, strings|
|
84
|
-
m = pattern.match(type) or next
|
85
|
-
break strings.map { |a| replace_backreferences(m, a) }
|
86
|
-
end
|
87
|
-
raise "Column type '#{type}' not supported" unless result
|
88
|
-
result
|
89
|
-
end
|
90
|
-
|
91
|
-
def column_def(str, create: true)
|
92
|
-
name, type = str.split(':')
|
93
|
-
format db_type(type)[create ? 0 : 1], name.downcase
|
94
|
-
end
|
95
|
-
|
96
|
-
def target(name)
|
97
|
-
raise "Migration filename is nil" unless name
|
98
|
-
"db/migrations/#{timestamp}_#{name}.rb"
|
99
|
-
end
|
100
|
-
|
101
|
-
private
|
102
|
-
|
103
|
-
def timestamp
|
104
|
-
DateTime.now.strftime("%Y%m%d%H%M%S")
|
105
|
-
end
|
106
|
-
|
107
|
-
def replace_backreferences(match, str)
|
108
|
-
groups = match.size
|
109
|
-
(1...groups).inject(str) do |s, i|
|
110
|
-
s.gsub("\\#{i}", match[i])
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def add_timestamp_columns?
|
115
|
-
if File.exist? 'config/initializers/sequel.rb'
|
116
|
-
require 'config/initializers/sequel'
|
117
|
-
Sequel::Model.plugins.include? Sequel::Plugins::Timestamps
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def render
|
122
|
-
<<~EOS
|
123
|
-
Sequel.migration do
|
124
|
-
change do
|
125
|
-
#{@changes.flatten.join("\n ")}
|
126
|
-
end
|
127
|
-
end
|
128
|
-
EOS
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
21
|
end
|
133
22
|
end
|
134
23
|
end
|
135
24
|
|
25
|
+
require 'shaf/generator/migration/base'
|
136
26
|
require 'shaf/generator/migration/add_column'
|
137
27
|
require 'shaf/generator/migration/add_index'
|
138
28
|
require 'shaf/generator/migration/create_table'
|
@@ -69,7 +69,7 @@ module Shaf
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def links
|
72
|
-
%w(doc:up self doc:
|
72
|
+
%w(doc:up self doc:edit-form doc:delete)
|
73
73
|
end
|
74
74
|
|
75
75
|
def curies_with_doc
|
@@ -83,7 +83,7 @@ module Shaf
|
|
83
83
|
# Example:
|
84
84
|
# ```
|
85
85
|
# curl -H "Accept: application/hal+json" \\
|
86
|
-
# /doc/#{name}/rels/
|
86
|
+
# /doc/#{name}/rels/delete
|
87
87
|
#```
|
88
88
|
curie :doc do
|
89
89
|
doc_curie_uri('#{name}')
|
@@ -96,9 +96,7 @@ module Shaf
|
|
96
96
|
[
|
97
97
|
collection_link,
|
98
98
|
self_link,
|
99
|
-
new_link,
|
100
99
|
edit_link,
|
101
|
-
update_link,
|
102
100
|
delete_link,
|
103
101
|
]
|
104
102
|
end
|
@@ -123,15 +121,6 @@ module Shaf
|
|
123
121
|
)
|
124
122
|
end
|
125
123
|
|
126
|
-
def new_link
|
127
|
-
link(
|
128
|
-
rel: "doc:create-form",
|
129
|
-
desc: "Link to a form to create a new #{name}",
|
130
|
-
uri: "/#{plural_name}/form",
|
131
|
-
uri_helper: "new_#{name}_uri"
|
132
|
-
)
|
133
|
-
end
|
134
|
-
|
135
124
|
def edit_link
|
136
125
|
link(
|
137
126
|
rel: "doc:edit-form",
|
@@ -141,16 +130,6 @@ module Shaf
|
|
141
130
|
)
|
142
131
|
end
|
143
132
|
|
144
|
-
def update_link
|
145
|
-
link(
|
146
|
-
rel: "doc:edit",
|
147
|
-
desc: "Link to update this #{name}",
|
148
|
-
method: "PUT",
|
149
|
-
uri: "/#{plural_name}/5",
|
150
|
-
uri_helper: "#{name}_uri(resource)"
|
151
|
-
)
|
152
|
-
end
|
153
|
-
|
154
133
|
def delete_link
|
155
134
|
link(
|
156
135
|
rel: "doc:delete",
|
@@ -194,38 +173,13 @@ module Shaf
|
|
194
173
|
EOS
|
195
174
|
end
|
196
175
|
|
197
|
-
def embeds
|
198
|
-
[:'doc:edit-form']
|
199
|
-
end
|
200
|
-
|
201
|
-
def embeds_with_doc
|
202
|
-
[
|
203
|
-
<<~EOS.split("\n")
|
204
|
-
# Auto generated doc:
|
205
|
-
# A form to edit this #{name}
|
206
|
-
embed :'doc:edit-form' do
|
207
|
-
resource.edit_form.tap do |form|
|
208
|
-
form.self_link = edit_#{name}_uri(resource)
|
209
|
-
form.href = #{name}_uri(resource)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
EOS
|
213
|
-
]
|
214
|
-
end
|
215
|
-
|
216
176
|
def collection_with_doc
|
217
177
|
<<~EOS.split("\n")
|
218
178
|
collection of: '#{plural_name}' do
|
219
179
|
link :self, #{plural_name}_uri
|
220
180
|
link :up, root_uri
|
181
|
+
link :'doc:create-form', new_#{name}_uri
|
221
182
|
curie(:doc) { doc_curie_uri('#{name}') }
|
222
|
-
|
223
|
-
embed :'doc:create-form' do
|
224
|
-
#{model_class_name}.create_form.tap do |form|
|
225
|
-
form.self_link = new_#{name}_uri
|
226
|
-
form.href = #{plural_name}_uri
|
227
|
-
end
|
228
|
-
end
|
229
183
|
end
|
230
184
|
EOS
|
231
185
|
end
|
@@ -239,11 +193,9 @@ module Shaf
|
|
239
193
|
policy_name: "#{name}_policy",
|
240
194
|
attributes: attributes,
|
241
195
|
links: links,
|
242
|
-
embeds: embeds,
|
243
196
|
attributes_with_doc: attributes_with_doc,
|
244
197
|
curies_with_doc: curies_with_doc,
|
245
198
|
links_with_doc: links_with_doc,
|
246
|
-
embeds_with_doc: embeds_with_doc,
|
247
199
|
collection_with_doc: collection_with_doc,
|
248
200
|
}
|
249
201
|
end
|
@@ -14,6 +14,7 @@ class <%= controller_class_name %> < BaseController
|
|
14
14
|
|
15
15
|
get :new_<%= name %>_uri do
|
16
16
|
authorize! :read
|
17
|
+
cache_control(:private, http_cache_max_age: :short)
|
17
18
|
respond_with create_form
|
18
19
|
end
|
19
20
|
|
@@ -31,6 +32,7 @@ class <%= controller_class_name %> < BaseController
|
|
31
32
|
|
32
33
|
get :edit_<%= name %>_uri do
|
33
34
|
authorize! :read
|
35
|
+
cache_control(:private, http_cache_max_age: :short)
|
34
36
|
respond_with edit_form
|
35
37
|
end
|
36
38
|
|
@@ -1,8 +1,7 @@
|
|
1
|
+
require 'serializers/base_serializer'
|
1
2
|
require 'policies/<%= policy_name %>'
|
2
3
|
|
3
|
-
class <%= class_name %>
|
4
|
-
extend HALPresenter
|
5
|
-
extend Shaf::UriHelper
|
4
|
+
class <%= class_name %> < BaseSerializer
|
6
5
|
|
7
6
|
model <%= model_class_name %>
|
8
7
|
policy <%= policy_class_name %>
|
@@ -15,9 +14,6 @@ class <%= class_name %>
|
|
15
14
|
<% links_with_doc.each do |link| %>
|
16
15
|
<%= link.join("\n ") %>
|
17
16
|
<% end %>
|
18
|
-
<% embeds_with_doc.each do |embed| %>
|
19
|
-
<%= embed.join("\n ") %>
|
20
|
-
<% end %>
|
21
17
|
<% if collection_with_doc %>
|
22
18
|
<%= collection_with_doc.join("\n ") %>
|
23
19
|
<% end %>
|
@@ -34,21 +34,21 @@ describe <%= model_class_name %>, type: :integration do
|
|
34
34
|
it "can create <%= plural_name %>" do
|
35
35
|
get <%= plural_name %>_uri
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
37
|
+
link_rels.must_include(:'doc:create-form')
|
38
|
+
follow_rel :'doc:create-form'
|
39
|
+
links[:self][:href].must_equal new_<%= name %>_uri
|
40
|
+
attributes[:href].must_equal <%= plural_name %>_uri
|
41
|
+
attributes[:method].must_equal "POST"
|
42
|
+
attributes[:name].must_equal "create-<%= name %>"
|
43
|
+
attributes[:title].must_equal "Create <%= model_class_name %>"
|
44
|
+
attributes[:type].must_equal "application/json"
|
45
|
+
attributes[:fields].size.must_equal <%= params.size %>
|
46
|
+
|
47
|
+
payload = fill_form attributes[:fields]
|
48
|
+
post attributes[:href], payload
|
49
|
+
status.must_equal 201
|
50
|
+
link_rels.must_include(:self)
|
51
|
+
headers["Location"].must_equal links[:self][:href]
|
52
52
|
|
53
53
|
get <%= plural_name %>_uri
|
54
54
|
status.must_equal 200
|
@@ -71,22 +71,22 @@ describe <%= model_class_name %>, type: :integration do
|
|
71
71
|
<%= name %> = <%= model_class_name %>.create
|
72
72
|
get <%= name %>_uri(<%= name %>)
|
73
73
|
status.must_equal 200
|
74
|
-
link_rels.must_include(:'doc:edit-form')
|
75
74
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
75
|
+
link_rels.must_include(:'doc:edit-form')
|
76
|
+
follow_rel :'doc:edit-form'
|
77
|
+
|
78
|
+
links[:self][:href].must_equal edit_<%= name %>_uri(<%= name %>)
|
79
|
+
attributes[:href].must_equal <%= name %>_uri(<%= name %>)
|
80
|
+
attributes[:method].must_equal "PUT"
|
81
|
+
attributes[:name].must_equal "update-<%= name %>"
|
82
|
+
attributes[:title].must_equal "Update <%= model_class_name %>"
|
83
|
+
attributes[:type].must_equal "application/json"
|
84
|
+
attributes[:fields].size.must_equal <%= params.size %>
|
85
|
+
|
86
|
+
payload = fill_form attributes[:fields]
|
87
|
+
put attributes[:href], payload
|
88
|
+
status.must_equal 200
|
89
|
+
link_rels.must_include(:self)
|
90
90
|
end
|
91
91
|
|
92
92
|
it "<%= plural_name %> can be deleted" do
|
data/lib/shaf/generator.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'erb'
|
3
|
-
require 'ostruct'
|
4
1
|
require 'shaf/registrable_factory'
|
5
2
|
|
6
3
|
module Shaf
|
@@ -8,63 +5,10 @@ module Shaf
|
|
8
5
|
class Factory
|
9
6
|
extend RegistrableFactory
|
10
7
|
end
|
11
|
-
|
12
|
-
class Base
|
13
|
-
attr_reader :args
|
14
|
-
|
15
|
-
class << self
|
16
|
-
def inherited(child)
|
17
|
-
Factory.register(child)
|
18
|
-
end
|
19
|
-
|
20
|
-
def identifier(*ids)
|
21
|
-
@identifiers = ids.flatten
|
22
|
-
end
|
23
|
-
|
24
|
-
def usage(str = nil, &block)
|
25
|
-
@usage = str || block
|
26
|
-
end
|
27
|
-
|
28
|
-
def options(option_parser, options); end
|
29
|
-
end
|
30
|
-
|
31
|
-
def initialize(*args)
|
32
|
-
@args = args.dup
|
33
|
-
end
|
34
|
-
|
35
|
-
def call(options = {}); end
|
36
|
-
|
37
|
-
def template_dir
|
38
|
-
File.expand_path('../generator/templates', __FILE__)
|
39
|
-
end
|
40
|
-
|
41
|
-
def read_template(file, directory = nil)
|
42
|
-
directory ||= template_dir
|
43
|
-
filename = File.join(directory, file)
|
44
|
-
filename << ".erb" unless filename.end_with?(".erb")
|
45
|
-
File.read(filename)
|
46
|
-
end
|
47
|
-
|
48
|
-
def render(template, locals = {})
|
49
|
-
str = read_template(template)
|
50
|
-
locals[:changes] ||= []
|
51
|
-
b = OpenStruct.new(locals).instance_eval { binding }
|
52
|
-
ERB.new(str, 0, '%-<>').result(b)
|
53
|
-
rescue SystemCallError => e
|
54
|
-
puts "Failed to render template #{template}: #{e.message}"
|
55
|
-
raise
|
56
|
-
end
|
57
|
-
|
58
|
-
def write_output(file, content)
|
59
|
-
dir = File.dirname(file)
|
60
|
-
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
61
|
-
File.write(file, content)
|
62
|
-
puts "Added: #{file}"
|
63
|
-
end
|
64
|
-
end
|
65
8
|
end
|
66
9
|
end
|
67
10
|
|
11
|
+
require 'shaf/generator/base'
|
68
12
|
require 'shaf/generator/controller'
|
69
13
|
require 'shaf/generator/migration'
|
70
14
|
require 'shaf/generator/model'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Shaf
|
2
|
+
module CacheControl
|
3
|
+
|
4
|
+
def cache_control(*args, **kwargs)
|
5
|
+
return unless Shaf::Settings.http_cache
|
6
|
+
set_max_age(kwargs)
|
7
|
+
super(*args, **kwargs)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def set_max_age(kwargs)
|
13
|
+
max_age = kwargs[:http_cache_max_age] or return
|
14
|
+
if max_age.is_a? Symbol
|
15
|
+
key = "http_cache_max_age_#{max_age}".to_sym
|
16
|
+
max_age = Settings.respond_to?(key) ? Settings.send(key) : 86400
|
17
|
+
kwargs[:http_cache_max_age] = max_age
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/shaf/helpers.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
require 'shaf/helpers/
|
1
|
+
require 'shaf/helpers/cache_control'
|
2
2
|
require 'shaf/helpers/json_html'
|
3
3
|
require 'shaf/helpers/paginate'
|
4
|
+
require 'shaf/helpers/payload'
|
4
5
|
|
5
6
|
module Shaf
|
6
7
|
def self.helpers
|
7
8
|
[
|
8
|
-
|
9
|
+
CacheControl,
|
9
10
|
JsonHtml,
|
10
11
|
Paginate,
|
12
|
+
Payload,
|
11
13
|
]
|
12
14
|
end
|
13
15
|
end
|
data/lib/shaf/rake/db.rb
CHANGED
@@ -3,22 +3,39 @@ require 'yaml'
|
|
3
3
|
module Shaf
|
4
4
|
module Upgrade
|
5
5
|
class Manifest
|
6
|
-
attr_reader :target_version, :
|
6
|
+
attr_reader :target_version, :files
|
7
7
|
|
8
|
-
def initialize(target_version:, patches:
|
8
|
+
def initialize(target_version:, patches: nil, add: nil, drop: nil)
|
9
9
|
@target_version = target_version
|
10
|
-
@
|
10
|
+
@files = {}
|
11
|
+
@files[:patch] = build_patterns(patches)
|
12
|
+
@files[:add] = add || {}
|
13
|
+
@files[:drop] = (drop || []).map { |d| Regexp.new(d) }
|
11
14
|
end
|
12
15
|
|
16
|
+
def patch_for(file)
|
17
|
+
first_match = files[:patch].find { |_, pattern| file =~ pattern }
|
18
|
+
(first_match || []).first
|
19
|
+
end
|
20
|
+
|
21
|
+
def drop?(file)
|
22
|
+
files[:drop].any? { |pattern| file =~ pattern }
|
23
|
+
end
|
24
|
+
|
25
|
+
def stats
|
26
|
+
"Add: #{files[:add].size}, " \
|
27
|
+
"Del: #{files[:drop].size}, " \
|
28
|
+
"Patch: #{files[:patch].size}"
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
13
33
|
def build_patterns(patches)
|
34
|
+
return {} unless patches
|
14
35
|
patches.each_with_object({}) do |(chksum, pattern), hash|
|
15
|
-
hash[chksum] =
|
36
|
+
hash[chksum] = Regexp.new(pattern)
|
16
37
|
end
|
17
38
|
end
|
18
|
-
|
19
|
-
def patch_name_for(file)
|
20
|
-
@patches.select { |_, pattern| pattern =~ file }.keys.first
|
21
|
-
end
|
22
39
|
end
|
23
40
|
end
|
24
41
|
end
|
@@ -29,3 +46,7 @@ end
|
|
29
46
|
# patches:
|
30
47
|
# cd5b0bf61070a9fd57e60c45e9aaf64a: config/database.rb
|
31
48
|
# 59783ecfa5f41b84c6fad734e7aa6a1d: Rakefile
|
49
|
+
# add:
|
50
|
+
# 8ece24b8c440675bd3d188155909431c: api/policies/base_policy.rb
|
51
|
+
# drop:
|
52
|
+
# - api/policies/base_policy.rb
|
data/lib/shaf/upgrade/package.rb
CHANGED
@@ -3,6 +3,7 @@ require 'zlib'
|
|
3
3
|
require 'set'
|
4
4
|
require 'digest'
|
5
5
|
require 'open3'
|
6
|
+
require 'fileutils'
|
6
7
|
|
7
8
|
module Shaf
|
8
9
|
module Upgrade
|
@@ -13,8 +14,8 @@ module Shaf
|
|
13
14
|
class VersionNotFoundError < UpgradeError; end
|
14
15
|
class VersionConflictError < UpgradeError; end
|
15
16
|
class ManifestNotFoundError < UpgradeError; end
|
16
|
-
class
|
17
|
-
class
|
17
|
+
class MissingFileError < UpgradeError; end
|
18
|
+
class FileNotInManifestError < UpgradeError; end
|
18
19
|
class BadChecksumError < UpgradeError; end
|
19
20
|
|
20
21
|
UPGRADE_FILES_PATH = File.join(Utils.gem_root, 'upgrades').freeze
|
@@ -50,10 +51,10 @@ module Shaf
|
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
53
|
-
def initialize(version)
|
54
|
+
def initialize(version, manifest = nil, files = {})
|
54
55
|
@version = Version.new(version)
|
55
|
-
@manifest =
|
56
|
-
@
|
56
|
+
@manifest = manifest
|
57
|
+
@files = files
|
57
58
|
end
|
58
59
|
|
59
60
|
def load
|
@@ -74,22 +75,15 @@ module Shaf
|
|
74
75
|
end
|
75
76
|
|
76
77
|
def apply(dir = nil)
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
patch = @patches[name]
|
81
|
-
apply_patch(file, patch)
|
82
|
-
end
|
78
|
+
apply_patches(dir)
|
79
|
+
apply_additions
|
80
|
+
apply_drops(dir)
|
83
81
|
end
|
84
82
|
|
85
83
|
def to_s
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
count = @patches.size
|
90
|
-
count_str = "#{count} patch#{count == 1 ? "" : "es"}"
|
91
|
-
"Shaf::Upgrade::Package for version #{@version}, containing #{count_str}"
|
92
|
-
end
|
84
|
+
str = "Shaf::Upgrade::Package for version #{@version}"
|
85
|
+
return str if @manifest.nil?
|
86
|
+
"#{str} (#{@manifest.stats})"
|
93
87
|
end
|
94
88
|
|
95
89
|
private
|
@@ -107,15 +101,17 @@ module Shaf
|
|
107
101
|
if filename == MANIFEST_FILENAME
|
108
102
|
parse_manifest content
|
109
103
|
else
|
110
|
-
@
|
104
|
+
@files[filename] = content
|
111
105
|
end
|
112
106
|
end
|
113
107
|
|
114
108
|
def parse_manifest(content)
|
115
|
-
|
109
|
+
hash = YAML.safe_load(content)
|
116
110
|
@manifest = Manifest.new(
|
117
|
-
target_version:
|
118
|
-
patches:
|
111
|
+
target_version: hash["target_version"],
|
112
|
+
patches: hash["patches"],
|
113
|
+
add: hash["add"],
|
114
|
+
drop: hash["drop"]
|
119
115
|
)
|
120
116
|
end
|
121
117
|
|
@@ -123,12 +119,18 @@ module Shaf
|
|
123
119
|
raise ManifestNotFoundError unless @manifest
|
124
120
|
raise VersionConflictError unless @version == @manifest.target_version
|
125
121
|
|
126
|
-
|
127
|
-
from_file = @patches.keys.to_set
|
128
|
-
raise MissingPatchError if from_file < from_manifest
|
129
|
-
raise PatchNotInManifestError if from_manifest < from_file
|
122
|
+
from_file = @files.keys.to_set
|
130
123
|
|
131
|
-
@
|
124
|
+
manifest_patches = @manifest.files[:patch].keys.to_set
|
125
|
+
raise MissingFileError if from_file < manifest_patches
|
126
|
+
|
127
|
+
|
128
|
+
to_add = @manifest.files[:add].keys.to_set
|
129
|
+
raise MissingFileError if from_file < to_add
|
130
|
+
|
131
|
+
raise FileNotInManifestError if (manifest_patches + to_add) < from_file
|
132
|
+
|
133
|
+
@files.each do |md5, content|
|
132
134
|
raise BadChecksumError unless Digest::MD5.hexdigest(content) == md5
|
133
135
|
end
|
134
136
|
|
@@ -140,6 +142,15 @@ module Shaf
|
|
140
142
|
Dir["#{dir}**/*"]
|
141
143
|
end
|
142
144
|
|
145
|
+
def apply_patches(dir = nil)
|
146
|
+
files_in(dir).all? do |file|
|
147
|
+
name = @manifest.patch_for(file) # returns nil when file
|
148
|
+
next true unless name # shouldn't be patched
|
149
|
+
patch = @files[name]
|
150
|
+
apply_patch(file, patch)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
143
154
|
def apply_patch(file, patch)
|
144
155
|
success = nil
|
145
156
|
Open3.popen3('patch', file, '-r', '-') do |i, o, e, t|
|
@@ -153,6 +164,19 @@ module Shaf
|
|
153
164
|
success
|
154
165
|
end
|
155
166
|
|
167
|
+
def apply_additions
|
168
|
+
@manifest.files[:add].each do |chksum, filename|
|
169
|
+
content = @files[chksum]
|
170
|
+
FileUtils.mkdir_p File.dirname(filename)
|
171
|
+
File.open(filename, 'w') { |file| file.write(content) }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def apply_drops(dir = nil)
|
176
|
+
files_in(dir).map do |file|
|
177
|
+
File.unlink(file) if @manifest.drop?(file)
|
178
|
+
end
|
179
|
+
end
|
156
180
|
end
|
157
181
|
end
|
158
182
|
end
|
data/lib/shaf/version.rb
CHANGED