shaf 0.3.1 → 0.4.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
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/bin/shaf +3 -0
- data/lib/shaf.rb +1 -0
- data/lib/shaf/api_doc/document.rb +0 -1
- data/lib/shaf/app.rb +1 -1
- data/lib/shaf/command.rb +19 -2
- data/lib/shaf/command/generate.rb +11 -1
- data/lib/shaf/command/new.rb +1 -6
- data/lib/shaf/command/server.rb +7 -0
- data/lib/shaf/command/upgrade.rb +38 -0
- data/lib/shaf/extensions/authorize.rb +8 -6
- data/lib/shaf/extensions/resource_uris.rb +129 -71
- data/lib/shaf/generator.rb +4 -0
- data/lib/shaf/generator/controller.rb +2 -2
- data/lib/shaf/generator/migration.rb +33 -14
- data/lib/shaf/generator/migration/add_column.rb +1 -3
- data/lib/shaf/generator/migration/add_index.rb +42 -0
- data/lib/shaf/generator/model.rb +4 -4
- data/lib/shaf/generator/policy.rb +1 -1
- data/lib/shaf/generator/scaffold.rb +3 -3
- data/lib/shaf/generator/serializer.rb +5 -5
- data/lib/shaf/rake.rb +5 -0
- data/lib/shaf/rake/db.rb +79 -0
- data/lib/shaf/rake/test.rb +32 -0
- data/lib/shaf/registrable_factory.rb +8 -3
- data/lib/shaf/settings.rb +20 -4
- data/lib/shaf/tasks.rb +6 -3
- data/lib/shaf/{api_doc/task.rb → tasks/api_doc_task.rb} +6 -5
- data/lib/shaf/tasks/db_task.rb +42 -0
- data/lib/shaf/tasks/test_task.rb +16 -0
- data/lib/shaf/upgrade.rb +3 -0
- data/lib/shaf/upgrade/manifest.rb +31 -0
- data/lib/shaf/upgrade/package.rb +158 -0
- data/lib/shaf/upgrade/version.rb +52 -0
- data/lib/shaf/utils.rb +30 -0
- data/lib/shaf/version.rb +1 -1
- data/templates/Rakefile +2 -3
- data/templates/config/database.rb +3 -3
- metadata +33 -202
- metadata.gz.sig +0 -0
- data/lib/shaf/api_doc.rb +0 -3
- data/lib/shaf/tasks/db.rb +0 -81
- data/lib/shaf/tasks/test.rb +0 -48
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'shaf/api_doc/document'
|
2
|
+
require 'shaf/api_doc/comment'
|
2
3
|
|
3
4
|
module Shaf
|
4
|
-
module
|
5
|
-
class
|
5
|
+
module Tasks
|
6
|
+
class ApiDocTask
|
6
7
|
include Rake::DSL
|
7
8
|
|
8
9
|
attr_accessor :document_class, :source_dir, :html_output_dir, :yaml_output_dir
|
@@ -10,7 +11,7 @@ module Shaf
|
|
10
11
|
def initialize
|
11
12
|
yield self if block_given?
|
12
13
|
validate_attributes!
|
13
|
-
@document_class ||= Document
|
14
|
+
@document_class ||= ApiDoc::Document
|
14
15
|
define_tasks
|
15
16
|
end
|
16
17
|
|
@@ -48,7 +49,7 @@ module Shaf
|
|
48
49
|
|
49
50
|
def read_file(file)
|
50
51
|
doc = document_class.new
|
51
|
-
comment = Comment.new
|
52
|
+
comment = ApiDoc::Comment.new
|
52
53
|
|
53
54
|
File.readlines(file).each do |line|
|
54
55
|
next if empty_line?(line)
|
@@ -59,7 +60,7 @@ module Shaf
|
|
59
60
|
end
|
60
61
|
|
61
62
|
parse_line(line, doc, comment)
|
62
|
-
comment = Comment.new
|
63
|
+
comment = ApiDoc::Comment.new
|
63
64
|
end
|
64
65
|
|
65
66
|
return doc unless block_given?
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Shaf
|
2
|
+
module Tasks
|
3
|
+
class DbTask
|
4
|
+
include Rake::DSL
|
5
|
+
|
6
|
+
def initialize(name, description:, args: [], &block)
|
7
|
+
@name = name
|
8
|
+
@desc = description
|
9
|
+
@args = args
|
10
|
+
@block = block
|
11
|
+
define_task
|
12
|
+
end
|
13
|
+
|
14
|
+
def define_task
|
15
|
+
namespace :db do
|
16
|
+
desc @desc
|
17
|
+
task @name, @args do |t, args|
|
18
|
+
require 'config/database'
|
19
|
+
Sequel.extension :migration
|
20
|
+
instance_exec(t, args, &@block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def migrations
|
26
|
+
@migrations ||= DB[:schema_migrations].all
|
27
|
+
end
|
28
|
+
|
29
|
+
def last_migration
|
30
|
+
DB[:schema_migrations].order(:filename).last
|
31
|
+
end
|
32
|
+
|
33
|
+
def extract_version_and_filename(filename)
|
34
|
+
return [] unless filename
|
35
|
+
filename = filename[:filename] if filename.is_a? Hash
|
36
|
+
match = /(\d*)_(.*).rb/.match(filename)
|
37
|
+
return [] unless match
|
38
|
+
match[1..2]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
module Shaf
|
4
|
+
module Tasks
|
5
|
+
class TestTask < Rake::TestTask
|
6
|
+
def initialize(*args)
|
7
|
+
super(*args) do |t|
|
8
|
+
t.libs = %w(. api spec)
|
9
|
+
t.verbose = true
|
10
|
+
t.warning = false
|
11
|
+
yield self if block_given?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/shaf/upgrade.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Shaf
|
4
|
+
module Upgrade
|
5
|
+
class Manifest
|
6
|
+
attr_reader :target_version, :patches
|
7
|
+
|
8
|
+
def initialize(target_version:, patches: {})
|
9
|
+
@target_version = target_version
|
10
|
+
@patches = build_patterns(patches)
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_patterns(patches)
|
14
|
+
patches.each_with_object({}) do |(chksum, pattern), hash|
|
15
|
+
hash[chksum] = /#{pattern}/
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def patch_name_for(file)
|
20
|
+
@patches.select { |_, pattern| pattern =~ file }.keys.first
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Example of manifest:
|
27
|
+
# ---
|
28
|
+
# target_version: 0.4.0
|
29
|
+
# patches:
|
30
|
+
# cd5b0bf61070a9fd57e60c45e9aaf64a: config/database.rb
|
31
|
+
# 59783ecfa5f41b84c6fad734e7aa6a1d: Rakefile
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'rubygems/package'
|
2
|
+
require 'zlib'
|
3
|
+
require 'set'
|
4
|
+
require 'digest'
|
5
|
+
require 'open3'
|
6
|
+
|
7
|
+
module Shaf
|
8
|
+
module Upgrade
|
9
|
+
class Package
|
10
|
+
include Comparable
|
11
|
+
|
12
|
+
class UpgradeError < StandardError; end
|
13
|
+
class VersionNotFoundError < UpgradeError; end
|
14
|
+
class VersionConflictError < UpgradeError; end
|
15
|
+
class ManifestNotFoundError < UpgradeError; end
|
16
|
+
class MissingPatchError < UpgradeError; end
|
17
|
+
class PatchNotInManifestError < UpgradeError; end
|
18
|
+
class BadChecksumError < UpgradeError; end
|
19
|
+
|
20
|
+
UPGRADE_FILES_PATH = File.join(Utils.gem_root, 'upgrades').freeze
|
21
|
+
MANIFEST_FILENAME = 'manifest'.freeze
|
22
|
+
|
23
|
+
attr_reader :version
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def all
|
27
|
+
target_versions.map(&method(:new))
|
28
|
+
end
|
29
|
+
|
30
|
+
def load(version)
|
31
|
+
v = strip_suffix(version)
|
32
|
+
raise VersionNotFoundError unless target_versions.include? v
|
33
|
+
new(v).tap(&:load)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def target_versions
|
39
|
+
return @target_versions if @target_versions
|
40
|
+
|
41
|
+
files = Dir[File.join(UPGRADE_FILES_PATH, '*.tar.gz')]
|
42
|
+
@target_versions = files.each_with_object([]) do |file, versions|
|
43
|
+
str = File.basename(file, '.tar.gz')
|
44
|
+
versions << Version.new(str)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def strip_suffix(file)
|
49
|
+
file.sub('.tar.gz', '')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize(version)
|
54
|
+
@version = Version.new(version)
|
55
|
+
@manifest = nil
|
56
|
+
@patches = {}
|
57
|
+
end
|
58
|
+
|
59
|
+
def load
|
60
|
+
File.open(tarball, 'rb') do |file|
|
61
|
+
Zlib::GzipReader.wrap(file) do |gz|
|
62
|
+
Gem::Package::TarReader.new(gz) do |tar|
|
63
|
+
tar.each(&method(:add_tar_entry))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
validate
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def <=>(other)
|
72
|
+
version = other.is_a?(String) ? other : other.version
|
73
|
+
@version <=> version
|
74
|
+
end
|
75
|
+
|
76
|
+
def apply(dir = nil)
|
77
|
+
files_in(dir).all? do |file|
|
78
|
+
name = @manifest.patch_name_for(file) # returns nil when file
|
79
|
+
next true unless name # shouldn't be patched
|
80
|
+
patch = @patches[name]
|
81
|
+
apply_patch(file, patch)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_s
|
86
|
+
if @manifest.nil?
|
87
|
+
"Shaf::Upgrade::Package for version #{@version}"
|
88
|
+
else
|
89
|
+
count = @patches.size
|
90
|
+
count_str = "#{count} patch#{count == 1 ? "" : "es"}"
|
91
|
+
"Shaf::Upgrade::Package for version #{@version}, containing #{count_str}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def tarball
|
98
|
+
file = File.join(UPGRADE_FILES_PATH, "#{@version}.tar.gz")
|
99
|
+
return file if File.exist? file
|
100
|
+
raise VersionNotFoundError
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_tar_entry(entry)
|
104
|
+
filename = entry.full_name
|
105
|
+
content = entry.read
|
106
|
+
|
107
|
+
if filename == MANIFEST_FILENAME
|
108
|
+
parse_manifest content
|
109
|
+
else
|
110
|
+
@patches[filename] = content
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def parse_manifest(content)
|
115
|
+
h = YAML.safe_load(content)
|
116
|
+
@manifest = Manifest.new(
|
117
|
+
target_version: h['target_version'],
|
118
|
+
patches: h['patches']
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
def validate
|
123
|
+
raise ManifestNotFoundError unless @manifest
|
124
|
+
raise VersionConflictError unless @version == @manifest.target_version
|
125
|
+
|
126
|
+
from_manifest = @manifest.patches.keys.to_set
|
127
|
+
from_file = @patches.keys.to_set
|
128
|
+
raise MissingPatchError if from_file < from_manifest
|
129
|
+
raise PatchNotInManifestError if from_manifest < from_file
|
130
|
+
|
131
|
+
@patches.each do |md5, content|
|
132
|
+
raise BadChecksumError unless Digest::MD5.hexdigest(content) == md5
|
133
|
+
end
|
134
|
+
|
135
|
+
true
|
136
|
+
end
|
137
|
+
|
138
|
+
def files_in(dir)
|
139
|
+
dir += '/' if !dir.nil? && dir[-1] != '/'
|
140
|
+
Dir["#{dir}**/*"]
|
141
|
+
end
|
142
|
+
|
143
|
+
def apply_patch(file, patch)
|
144
|
+
success = nil
|
145
|
+
Open3.popen3('patch', file, '-r', '-') do |i, o, e, t|
|
146
|
+
i.write patch
|
147
|
+
i.close
|
148
|
+
puts o.read
|
149
|
+
err = e.read
|
150
|
+
puts err unless err.empty?
|
151
|
+
success = t.value.success?
|
152
|
+
end
|
153
|
+
success
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Shaf
|
2
|
+
module Upgrade
|
3
|
+
class Version
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
attr_reader :major, :minor, :patch
|
7
|
+
|
8
|
+
alias eql? ==
|
9
|
+
|
10
|
+
class UpgradeVersionError < StandardError
|
11
|
+
def initialize(message = "")
|
12
|
+
super("Bad upgrade version: #{message}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(version)
|
17
|
+
if self.class === version
|
18
|
+
@major, @minor, @patch = [:major, :minor, :patch].map { |m| version.send m }
|
19
|
+
else
|
20
|
+
raise UpgradeVersionError.new(version) unless version =~ /\d+\.\d+\.\d+/
|
21
|
+
@major, @minor, @patch = split_version(version)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def <=>(other)
|
26
|
+
if other.is_a? String
|
27
|
+
compare_version(*split_version(other))
|
28
|
+
else
|
29
|
+
compare_version(other.major, other.minor, other.patch)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
[major, minor, patch].join('.')
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def split_version(str)
|
40
|
+
str.split('.').map(&:to_i)
|
41
|
+
end
|
42
|
+
|
43
|
+
def compare_version(other_major, other_minor, other_patch)
|
44
|
+
[
|
45
|
+
major <=> other_major,
|
46
|
+
minor <=> other_minor,
|
47
|
+
patch <=> other_patch
|
48
|
+
].find { |x| !x.zero? } || 0
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/shaf/utils.rb
CHANGED
@@ -2,6 +2,8 @@ module Shaf
|
|
2
2
|
module Utils
|
3
3
|
class ProjectRootNotFound < StandardError; end
|
4
4
|
|
5
|
+
SHAF_VERSION_FILE = '.shaf'.freeze
|
6
|
+
|
5
7
|
# FIXME!!!
|
6
8
|
def self.pluralize(noun)
|
7
9
|
noun + 's' # FIXME!!
|
@@ -11,6 +13,10 @@ module Shaf
|
|
11
13
|
name.capitalize.gsub(/[_-](\w)/) { $1.upcase }
|
12
14
|
end
|
13
15
|
|
16
|
+
def self.gem_root
|
17
|
+
File.expand_path('../../..', __FILE__)
|
18
|
+
end
|
19
|
+
|
14
20
|
# FIXME!!!
|
15
21
|
def self.singularize(noun)
|
16
22
|
return singularize(noun.to_s).to_sym if noun.is_a? Symbol
|
@@ -18,6 +24,10 @@ module Shaf
|
|
18
24
|
noun[0..-2]
|
19
25
|
end
|
20
26
|
|
27
|
+
def gem_root
|
28
|
+
self.class.gem_root
|
29
|
+
end
|
30
|
+
|
21
31
|
def project_root
|
22
32
|
dir = Dir.pwd
|
23
33
|
20.times do
|
@@ -61,5 +71,25 @@ module Shaf
|
|
61
71
|
def pluralize(noun)
|
62
72
|
Utils::pluralize(noun)
|
63
73
|
end
|
74
|
+
|
75
|
+
def read_shaf_file
|
76
|
+
return {} unless File.exist? SHAF_VERSION_FILE
|
77
|
+
str = File.read(SHAF_VERSION_FILE)
|
78
|
+
YAML.load(str) || {}
|
79
|
+
end
|
80
|
+
|
81
|
+
def write_shaf_file(data = {})
|
82
|
+
data = read_shaf_file.merge(data)
|
83
|
+
File.write SHAF_VERSION_FILE,
|
84
|
+
YAML.dump(data)
|
85
|
+
end
|
86
|
+
|
87
|
+
def read_shaf_version
|
88
|
+
read_shaf_file['version']
|
89
|
+
end
|
90
|
+
|
91
|
+
def write_shaf_version(version = nil)
|
92
|
+
write_shaf_file('version' => version || Shaf::VERSION)
|
93
|
+
end
|
64
94
|
end
|
65
95
|
end
|
data/lib/shaf/version.rb
CHANGED
data/templates/Rakefile
CHANGED
@@ -2,11 +2,10 @@ require 'rubygems'
|
|
2
2
|
require 'bundler'
|
3
3
|
Bundler.setup(:default, :development)
|
4
4
|
$:.unshift __dir__
|
5
|
-
require 'shaf/
|
5
|
+
require 'shaf/rake'
|
6
6
|
require 'shaf/settings'
|
7
|
-
require 'shaf/api_doc'
|
8
7
|
|
9
|
-
Shaf::
|
8
|
+
Shaf::ApiDocTask.new do |api_doc|
|
10
9
|
api_doc.source_dir = File.join(%w(api serializers))
|
11
10
|
api_doc.html_output_dir = File.join(Shaf::Settings.public_folder, "doc")
|
12
11
|
api_doc.yaml_output_dir = Shaf::Settings.documents_dir || "doc/api"
|
@@ -3,7 +3,7 @@ require 'sequel'
|
|
3
3
|
require 'config/constants'
|
4
4
|
require 'fileutils'
|
5
5
|
|
6
|
-
|
6
|
+
config = {
|
7
7
|
|
8
8
|
production: {
|
9
9
|
adapter: 'postgres',
|
@@ -28,7 +28,7 @@ CONFIG = {
|
|
28
28
|
|
29
29
|
env = Sinatra::Application.settings.environment
|
30
30
|
|
31
|
-
unless
|
31
|
+
unless config[env]
|
32
32
|
STDERR.puts "No Database config for environment '#{env}'"
|
33
33
|
exit 1
|
34
34
|
end
|
@@ -36,5 +36,5 @@ end
|
|
36
36
|
MIGRATIONS_DIR = File.join(APP_ROOT, Shaf::Settings.migrations_dir)
|
37
37
|
FileUtils.mkdir_p(MIGRATIONS_DIR) unless Dir.exist?(MIGRATIONS_DIR)
|
38
38
|
|
39
|
-
DB = Sequel.connect(
|
39
|
+
DB = Sequel.connect(config[env])
|
40
40
|
|