-
Notifications
You must be signed in to change notification settings - Fork 2
/
.gemspec
306 lines (257 loc) · 7.26 KB
/
.gemspec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# encoding: utf-8
require 'yaml'
require 'pathname'
module Indexer
# Convert index data into a gemspec.
#
# Notes:
# * Assumes all executables are in bin/.
# * Does not yet handle default_executable setting.
# * Does not yet handle platform setting.
# * Does not yet handle required_ruby_version.
# * Support for rdoc entries is weak.
#
class GemspecExporter
# File globs to include in package (unless manifest file exists).
FILES = ".index .ruby .yardopts alt bin ext lib man spec test [A-Z]*.*" unless defined?(FILES)
# File globs to omit.
OMIT = "Config.rb" unless defined?(OMIT)
# Standard file patterns.
PATTERNS = {
:root => '{.index,Gemfile}',
:bin => 'bin/*',
:lib => 'lib/{**/}*', #.rb',
:ext => 'ext/{**/}extconf.rb',
:doc => '*.{txt,rdoc,md,markdown,tt,textile}',
:test => '{test,spec}/{**/}*.rb'
} unless defined?(PATTERNS)
# For which revision of indexer spec is this converter intended?
REVISION = 2013 unless defined?(REVISION)
#
def self.gemspec
new.to_gemspec
end
#
attr :metadata
#
def initialize(metadata=nil)
@root_check = false
if metadata
root_dir = metadata.delete(:root)
if root_dir
@root = root_dir
@root_check = true
end
metadata = nil if metadata.empty?
end
@metadata = metadata || YAML.load_file(root + '.index')
if @metadata['revision'].to_i != REVISION
warn "This gemspec exporter was not designed for this revision of index metadata."
end
end
#
def has_root?
root ? true : false
end
#
def root
return @root if @root || @root_check
@root_check = true
@root = find_root
end
#
def manifest
return nil unless root
@manifest ||= Dir.glob(root + 'manifest{,.txt}', File::FNM_CASEFOLD).first
end
#
def scm
return nil unless root
@scm ||= %w{git hg}.find{ |m| (root + ".#{m}").directory? }.to_sym
end
#
def files
return [] unless root
@files ||= \
if manifest
File.readlines(manifest).
map{ |line| line.strip }.
reject{ |line| line.empty? || line[0,1] == '#' }
else
list = []
Dir.chdir(root) do
FILES.split(/\s+/).each do |pattern|
list.concat(glob(pattern))
end
OMIT.split(/\s+/).each do |pattern|
list = list - glob(pattern)
end
end
list
end.select{ |path| File.file?(path) }.uniq
end
#
def glob_files(pattern)
return [] unless root
Dir.chdir(root) do
Dir.glob(pattern).select do |path|
File.file?(path) && files.include?(path)
end
end
end
def patterns
PATTERNS
end
def executables
@executables ||= \
glob_files(patterns[:bin]).map do |path|
File.basename(path)
end
end
def extensions
@extensions ||= \
glob_files(patterns[:ext]).map do |path|
File.basename(path)
end
end
def name
metadata['name'] || metadata['title'].downcase.gsub(/\W+/,'_')
end
def homepage
page = (
metadata['resources'].find{ |r| r['type'] =~ /^home/i } ||
metadata['resources'].find{ |r| r['name'] =~ /^home/i } ||
metadata['resources'].find{ |r| r['name'] =~ /^web/i }
)
page ? page['uri'] : false
end
def licenses
metadata['copyrights'].map{ |c| c['license'] }.compact
end
def require_paths
metadata['load_path'] || ['lib']
end
#
# Convert to gemnspec.
#
def to_gemspec
if has_root?
Gem::Specification.new do |gemspec|
to_gemspec_data(gemspec)
to_gemspec_paths(gemspec)
end
else
Gem::Specification.new do |gemspec|
to_gemspec_data(gemspec)
to_gemspec_paths(gemspec)
end
end
end
#
# Convert pure data settings.
#
def to_gemspec_data(gemspec)
gemspec.name = name
gemspec.version = metadata['version']
gemspec.summary = metadata['summary']
gemspec.description = metadata['description']
metadata['authors'].each do |author|
gemspec.authors << author['name']
if author.has_key?('email')
if gemspec.email
gemspec.email << author['email']
else
gemspec.email = [author['email']]
end
end
end
gemspec.licenses = licenses
requirements = metadata['requirements'] || []
requirements.each do |req|
next if req['optional']
next if req['external']
name = req['name']
groups = req['groups'] || []
version = gemify_version(req['version'])
if groups.empty? or groups.include?('runtime')
# populate runtime dependencies
if gemspec.respond_to?(:add_runtime_dependency)
gemspec.add_runtime_dependency(name,*version)
else
gemspec.add_dependency(name,*version)
end
else
# populate development dependencies
if gemspec.respond_to?(:add_development_dependency)
gemspec.add_development_dependency(name,*version)
else
gemspec.add_dependency(name,*version)
end
end
end
# convert external dependencies into gemspec requirements
requirements.each do |req|
next unless req['external']
gemspec.requirements << ("%s-%s" % req.values_at('name', 'version'))
end
gemspec.homepage = homepage
gemspec.require_paths = require_paths
gemspec.post_install_message = metadata['install_message']
end
#
# Set gemspec settings that require a root directory path.
#
def to_gemspec_paths(gemspec)
gemspec.files = files
gemspec.extensions = extensions
gemspec.executables = executables
if Gem::VERSION < '1.7.'
gemspec.default_executable = gemspec.executables.first
end
gemspec.test_files = glob_files(patterns[:test])
unless gemspec.files.include?('.document')
gemspec.extra_rdoc_files = glob_files(patterns[:doc])
end
end
#
# Return a copy of this file. This is used to generate a local
# .gemspec file that can automatically read the index file.
#
def self.source_code
File.read(__FILE__)
end
private
def find_root
root_files = patterns[:root]
if Dir.glob(root_files).first
Pathname.new(Dir.pwd)
elsif Dir.glob("../#{ROOT}").first
Pathname.new(Dir.pwd).parent
else
#raise "Can't find root of project containing `#{root_files}'."
warn "Can't find root of project containing `#{root_files}'."
nil
end
end
def glob(pattern)
if File.directory?(pattern)
Dir.glob(File.join(pattern, '**', '*'))
else
Dir.glob(pattern)
end
end
def gemify_version(version)
case version
when /^(.*?)\+$/
">= #{$1}"
when /^(.*?)\-$/
"< #{$1}"
when /^(.*?)\~$/
"~> #{$1}"
else
version
end
end
end
end
Indexer::GemspecExporter.gemspec