realityforge-buildr 1.5.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE +176 -0
  4. data/NOTICE +26 -0
  5. data/README.md +3 -0
  6. data/Rakefile +50 -0
  7. data/addon/buildr/checkstyle-report.xsl +104 -0
  8. data/addon/buildr/checkstyle.rb +254 -0
  9. data/addon/buildr/git_auto_version.rb +36 -0
  10. data/addon/buildr/gpg.rb +90 -0
  11. data/addon/buildr/gwt.rb +413 -0
  12. data/addon/buildr/jacoco.rb +161 -0
  13. data/addon/buildr/pmd.rb +185 -0
  14. data/addon/buildr/single_intermediate_layout.rb +71 -0
  15. data/addon/buildr/spotbugs.rb +265 -0
  16. data/addon/buildr/top_level_generate_dir.rb +37 -0
  17. data/addon/buildr/wsgen.rb +192 -0
  18. data/bin/buildr +20 -0
  19. data/buildr.gemspec +61 -0
  20. data/lib/buildr.rb +86 -0
  21. data/lib/buildr/core/application.rb +705 -0
  22. data/lib/buildr/core/assets.rb +96 -0
  23. data/lib/buildr/core/build.rb +587 -0
  24. data/lib/buildr/core/common.rb +167 -0
  25. data/lib/buildr/core/compile.rb +599 -0
  26. data/lib/buildr/core/console.rb +124 -0
  27. data/lib/buildr/core/doc.rb +275 -0
  28. data/lib/buildr/core/environment.rb +128 -0
  29. data/lib/buildr/core/filter.rb +405 -0
  30. data/lib/buildr/core/help.rb +114 -0
  31. data/lib/buildr/core/progressbar.rb +161 -0
  32. data/lib/buildr/core/project.rb +994 -0
  33. data/lib/buildr/core/test.rb +776 -0
  34. data/lib/buildr/core/transports.rb +456 -0
  35. data/lib/buildr/core/util.rb +77 -0
  36. data/lib/buildr/ide/idea.rb +1664 -0
  37. data/lib/buildr/java/commands.rb +230 -0
  38. data/lib/buildr/java/compiler.rb +85 -0
  39. data/lib/buildr/java/custom_pom.rb +300 -0
  40. data/lib/buildr/java/doc.rb +62 -0
  41. data/lib/buildr/java/packaging.rb +393 -0
  42. data/lib/buildr/java/pom.rb +191 -0
  43. data/lib/buildr/java/test_result.rb +54 -0
  44. data/lib/buildr/java/tests.rb +111 -0
  45. data/lib/buildr/packaging/archive.rb +586 -0
  46. data/lib/buildr/packaging/artifact.rb +1113 -0
  47. data/lib/buildr/packaging/artifact_namespace.rb +1010 -0
  48. data/lib/buildr/packaging/artifact_search.rb +138 -0
  49. data/lib/buildr/packaging/package.rb +237 -0
  50. data/lib/buildr/packaging/version_requirement.rb +189 -0
  51. data/lib/buildr/packaging/zip.rb +189 -0
  52. data/lib/buildr/packaging/ziptask.rb +387 -0
  53. data/lib/buildr/version.rb +18 -0
  54. data/rakelib/release.rake +99 -0
  55. data/spec/addon/checkstyle_spec.rb +58 -0
  56. data/spec/core/application_spec.rb +576 -0
  57. data/spec/core/build_spec.rb +922 -0
  58. data/spec/core/common_spec.rb +670 -0
  59. data/spec/core/compile_spec.rb +656 -0
  60. data/spec/core/console_spec.rb +65 -0
  61. data/spec/core/doc_spec.rb +194 -0
  62. data/spec/core/extension_spec.rb +200 -0
  63. data/spec/core/project_spec.rb +736 -0
  64. data/spec/core/test_spec.rb +1131 -0
  65. data/spec/core/transport_spec.rb +452 -0
  66. data/spec/core/util_spec.rb +154 -0
  67. data/spec/ide/idea_spec.rb +1952 -0
  68. data/spec/java/commands_spec.rb +79 -0
  69. data/spec/java/compiler_spec.rb +274 -0
  70. data/spec/java/custom_pom_spec.rb +165 -0
  71. data/spec/java/doc_spec.rb +55 -0
  72. data/spec/java/packaging_spec.rb +786 -0
  73. data/spec/java/pom_spec.rb +162 -0
  74. data/spec/java/test_coverage_helper.rb +257 -0
  75. data/spec/java/tests_spec.rb +224 -0
  76. data/spec/packaging/archive_spec.rb +686 -0
  77. data/spec/packaging/artifact_namespace_spec.rb +757 -0
  78. data/spec/packaging/artifact_spec.rb +1351 -0
  79. data/spec/packaging/packaging_helper.rb +63 -0
  80. data/spec/packaging/packaging_spec.rb +690 -0
  81. data/spec/sandbox.rb +166 -0
  82. data/spec/spec_helpers.rb +420 -0
  83. data/spec/version_requirement_spec.rb +145 -0
  84. data/spec/xpath_matchers.rb +123 -0
  85. metadata +295 -0
@@ -0,0 +1,456 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+ require 'net/http'
17
+ autoload :CGI, 'cgi'
18
+ require 'digest/md5'
19
+ require 'digest/sha1'
20
+ autoload :ProgressBar, 'buildr/core/progressbar'
21
+
22
+ # Not quite open-uri, but similar. Provides read and write methods for the resource represented by the URI.
23
+ # Currently supports reads for URI::HTTP. Also provides convenience methods for
24
+ # downloads and uploads.
25
+ module URI
26
+
27
+ # Raised when trying to read/download a resource that doesn't exist.
28
+ class NotFoundError < RuntimeError
29
+ end
30
+
31
+ # How many bytes to read/write at once. Do not change without checking BUILDR-214 first.
32
+ RW_CHUNK_SIZE = 128 * 1024 #:nodoc:
33
+
34
+ class << self
35
+ # :call-seq:
36
+ # read(uri, options?) => content
37
+ # read(uri, options?) { |chunk| ... }
38
+ #
39
+ # Reads from the resource behind this URI. The first form returns the content of the resource,
40
+ # the second form yields to the block with each chunk of content (usually more than one).
41
+ #
42
+ # For example:
43
+ # File.open 'image.jpg', 'w' do |file|
44
+ # URI.read('http://example.com/image.jpg') { |chunk| file.write chunk }
45
+ # end
46
+ # Shorter version:
47
+ # File.open('image.jpg', 'w') { |file| file.write URI.read('http://example.com/image.jpg') }
48
+ #
49
+ # Supported options:
50
+ # * :modified -- Only download if file modified since this timestamp. Returns nil if not modified.
51
+ # * :progress -- Show the progress bar while reading.
52
+ def read(uri, options = nil, &block)
53
+ uri = URI.parse(uri.to_s) unless URI === uri
54
+ uri.read options, &block
55
+ end
56
+
57
+ # :call-seq:
58
+ # download(uri, target, options?)
59
+ #
60
+ # Downloads the resource to the target.
61
+ #
62
+ # The target may be a file name (string or task), in which case the file is created from the resource.
63
+ # The target may also be any object that responds to +write+, e.g. File, StringIO, Pipe.
64
+ #
65
+ # Use the progress bar when running in verbose mode.
66
+ def download(uri, target, options = nil)
67
+ uri = URI.parse(uri.to_s) unless URI === uri
68
+ uri.download target, options
69
+ end
70
+
71
+ # :call-seq:
72
+ # write(uri, content, options?)
73
+ # write(uri, options?) { |bytes| .. }
74
+ #
75
+ # Writes to the resource behind the URI. The first form writes the content from a string or an object
76
+ # that responds to +read+ and optionally +size+. The second form writes the content by yielding to the
77
+ # block. Each yield should return up to the specified number of bytes, the last yield returns nil.
78
+ #
79
+ # For example:
80
+ # File.open 'killer-app.jar', 'rb' do |file|
81
+ # write('https://localhost/jars/killer-app.jar') { |chunk| file.read(chunk) }
82
+ # end
83
+ # Or:
84
+ # write 'https://localhost/jars/killer-app.jar', File.read('killer-app.jar')
85
+ #
86
+ # Supported options:
87
+ # * :progress -- Show the progress bar while reading.
88
+ def write(uri, *args, &block)
89
+ uri = URI.parse(uri.to_s) unless URI === uri
90
+ uri.write *args, &block
91
+ end
92
+
93
+ # :call-seq:
94
+ # upload(uri, source, options?)
95
+ #
96
+ # Uploads from source to the resource.
97
+ #
98
+ # The source may be a file name (string or task), in which case the file is uploaded to the resource.
99
+ # The source may also be any object that responds to +read+ (and optionally +size+), e.g. File, StringIO, Pipe.
100
+ #
101
+ # Use the progress bar when running in verbose mode.
102
+ def upload(uri, source, options = nil)
103
+ uri = URI.parse(uri.to_s) unless URI === uri
104
+ uri.upload source, options
105
+ end
106
+
107
+ end
108
+
109
+ class Generic
110
+
111
+ # :call-seq:
112
+ # read(options?) => content
113
+ # read(options?) { |chunk| ... }
114
+ #
115
+ # Reads from the resource behind this URI. The first form returns the content of the resource,
116
+ # the second form yields to the block with each chunk of content (usually more than one).
117
+ #
118
+ # For options, see URI::read.
119
+ def read(options = nil, &block)
120
+ fail 'This protocol doesn\'t support reading (yet, how about helping by implementing it?)'
121
+ end
122
+
123
+ # :call-seq:
124
+ # download(target, options?)
125
+ #
126
+ # Downloads the resource to the target.
127
+ #
128
+ # The target may be a file name (string or task), in which case the file is created from the resource.
129
+ # The target may also be any object that responds to +write+, e.g. File, StringIO, Pipe.
130
+ #
131
+ # Use the progress bar when running in verbose mode.
132
+ def download(target, options = nil)
133
+ case target
134
+ when Rake::Task
135
+ download target.name, options
136
+ when String
137
+ # If download breaks we end up with a partial file which is
138
+ # worse than not having a file at all, so download to temporary
139
+ # file and then move over.
140
+ modified = ::File.stat(target).mtime if ::File.exist?(target)
141
+ temp = Tempfile.new(::File.basename(target))
142
+ temp.binmode
143
+ written = false
144
+ read({ :progress => verbose }.merge(options || {}).merge(:modified => modified)) { |chunk| written = true; temp.write chunk }
145
+ temp.close
146
+ mkpath ::File.dirname(target)
147
+ # Only attempt to override file if it was actually written to, i.e. "HTTP Not Modified" was not returned.
148
+ mv temp.path, target if written
149
+ when ::File
150
+ read({ :progress => verbose }.merge(options || {}).merge(:modified => target.mtime)) { |chunk| target.write chunk }
151
+ target.flush
152
+ else
153
+ raise ArgumentError, 'Expecting a target that is either a file name (string, task) or object that responds to write (file, pipe).' unless target.respond_to?(:write)
154
+ read({:progress=>verbose}.merge(options || {})) { |chunk| target.write chunk }
155
+ target.flush
156
+ end
157
+ end
158
+
159
+ # :call-seq:
160
+ # write(content, options?)
161
+ # write(options?) { |bytes| .. }
162
+ #
163
+ # Writes to the resource behind the URI. The first form writes the content from a string or an object
164
+ # that responds to +read+ and optionally +size+. The second form writes the content by yielding to the
165
+ # block. Each yield should return up to the specified number of bytes, the last yield returns nil.
166
+ #
167
+ # For options, see URI::write.
168
+ def write(*args, &block)
169
+ options = args.pop if Hash === args.last
170
+ options ||= {}
171
+ if String === args.first
172
+ ios = StringIO.new(args.first, 'r')
173
+ write(options.merge(:size=>args.first.size)) { |bytes| ios.read(bytes) }
174
+ elsif args.first.respond_to?(:read)
175
+ size = args.first.size rescue nil
176
+ write({:size=>size}.merge(options)) { |bytes| args.first.read(bytes) }
177
+ elsif args.empty? && block
178
+ write_internal options, &block
179
+ else
180
+ raise ArgumentError, 'Either give me the content, or pass me a block, otherwise what would I upload?'
181
+ end
182
+ end
183
+
184
+ # :call-seq:
185
+ # upload(source, options?)
186
+ #
187
+ # Uploads from source to the resource.
188
+ #
189
+ # The source may be a file name (string or task), in which case the file is uploaded to the resource.
190
+ # If the source is a directory, uploads all files inside the directory (including nested directories).
191
+ # The source may also be any object that responds to +read+ (and optionally +size+), e.g. File, StringIO, Pipe.
192
+ #
193
+ # Use the progress bar when running in verbose mode.
194
+ def upload(source, options = nil)
195
+ source = source.name if Rake::Task === source
196
+ options ||= {}
197
+ if String === source
198
+ raise NotFoundError, 'No source file/directory to upload.' unless ::File.exist?(source)
199
+ if ::File.directory?(source)
200
+ Dir.glob("#{source}/**/*").reject { |file| ::File.directory?(file) }.each do |file|
201
+ uri = self + (::File.join(self.path, file.sub(source, '')))
202
+ uri.upload file, { :digests => [] }.merge(options)
203
+ end
204
+ else
205
+ ::File.open(source, 'rb') { |input| upload input, options }
206
+ end
207
+ elsif source.respond_to?(:read)
208
+ digests = (options[:digests] || [:md5, :sha1]).
209
+ inject({}) { |hash, name| hash[name] = name.to_s == 'sha512' ? Digest::SHA2.new(512) : Digest.const_get(name.to_s.upcase).new ; hash}
210
+ size = source.stat.size rescue nil
211
+ write (options).merge(:progress=>verbose && size, :size=>size) do |bytes|
212
+ source.read(bytes).tap do |chunk|
213
+ digests.values.each { |digest| digest << chunk } if chunk
214
+ end
215
+ end
216
+ digests.each do |key, digest|
217
+ self.merge("#{self.path}.#{key}").write digest.hexdigest,
218
+ (options).merge(:progress=>false)
219
+ end
220
+ else
221
+ raise ArgumentError, 'Expecting source to be a file name (string, task) or any object that responds to read (file, pipe).'
222
+ end
223
+ end
224
+
225
+ protected
226
+
227
+ # :call-seq:
228
+ # with_progress_bar(show, file_name, size) { |progress| ... }
229
+ #
230
+ # Displays a progress bar while executing the block. The first argument must be true for the
231
+ # progress bar to show (TTY output also required), as a convenient for selectively using the
232
+ # progress bar from a single block.
233
+ #
234
+ # The second argument provides a filename to display, the third its size in bytes.
235
+ #
236
+ # The block is yielded with a progress object that implements a single method.
237
+ # Call << for each block of bytes down/uploaded.
238
+ def with_progress_bar(show, file_name, size, &block) #:nodoc:
239
+ options = { :total=>size || 0, :title=>file_name }
240
+ options[:hidden] = true unless show
241
+ ProgressBar.start options, &block
242
+ end
243
+
244
+ # :call-seq:
245
+ # proxy_uri => URI?
246
+ #
247
+ # Returns the proxy server to use. Obtains the proxy from the relevant environment variable (e.g. HTTP_PROXY).
248
+ # Supports exclusions based on host name and port number from environment variable NO_PROXY.
249
+ def proxy_uri
250
+ proxy = ENV["#{scheme.upcase}_PROXY"]
251
+ proxy = URI.parse(proxy) if String === proxy
252
+ excludes = ENV['NO_PROXY'].to_s.split(/\s*,\s*/).compact
253
+ excludes = excludes.map { |exclude| exclude =~ /:\d+$/ ? exclude : "#{exclude}:*" }
254
+ return proxy unless excludes.any? { |exclude| ::File.fnmatch(exclude, "#{host}:#{port}") }
255
+ end
256
+
257
+ def write_internal(options, &block) #:nodoc:
258
+ fail 'This protocol doesn\'t support writing (yet, how about helping by implementing it?)'
259
+ end
260
+
261
+ end
262
+
263
+
264
+ class HTTP #:nodoc:
265
+
266
+ # See URI::Generic#read
267
+ def read(options = nil, &block)
268
+ options ||= {}
269
+ connect do |http|
270
+ trace "Requesting #{self}"
271
+ headers = {}
272
+ headers['If-Modified-Since'] = CGI.rfc1123_date(options[:modified].utc) if options[:modified]
273
+ headers['Cache-Control'] = 'no-cache'
274
+ headers['User-Agent'] = "Buildr-#{Buildr::VERSION}"
275
+ request = Net::HTTP::Get.new(request_uri.empty? ? '/' : request_uri, headers)
276
+ request.basic_auth URI.decode(self.user), URI.decode(self.password) if self.user
277
+ http.verify_mode = ::OpenSSL::SSL.const_get(ENV['SSL_VERIFY_MODE']) if ENV['SSL_VERIFY_MODE']
278
+ http.ca_path = ENV['SSL_CA_CERTS'] if ENV['SSL_CA_CERTS']
279
+ http.request request do |response|
280
+ case response
281
+ when Net::HTTPNotModified
282
+ # No modification, nothing to do.
283
+ trace 'Not modified since last download'
284
+ return nil
285
+ when Net::HTTPRedirection
286
+ # Try to download from the new URI, handle relative redirects.
287
+ trace "Redirected to #{response['Location']}"
288
+ rself = self + URI.parse(response['Location'])
289
+ rself.user, rself.password = self.user, self.password
290
+ return rself.read(options, &block)
291
+ when Net::HTTPOK
292
+ info "Downloading #{self}"
293
+ result = nil
294
+ with_progress_bar options[:progress], path.split('/').last, response.content_length do |progress|
295
+ if block
296
+ response.read_body do |chunk|
297
+ block.call chunk
298
+ progress << chunk
299
+ end
300
+ else
301
+ result = ''
302
+ response.read_body do |chunk|
303
+ result << chunk
304
+ progress << chunk
305
+ end
306
+ end
307
+ end
308
+ return result
309
+ when Net::HTTPUnauthorized
310
+ raise NotFoundError, "Looking for #{self} but repository says Unauthorized/401."
311
+ when Net::HTTPNotFound
312
+ raise NotFoundError, "Looking for #{self} and all I got was a 404!"
313
+ else
314
+ raise RuntimeError, "Failed to download #{self}: #{response.message}"
315
+ end
316
+ end
317
+ end
318
+ end
319
+
320
+ private
321
+
322
+ def write_internal(options, &block) #:nodoc:
323
+ options ||= {}
324
+ connect do |http|
325
+ http.read_timeout = 500
326
+ trace "Uploading to #{path}"
327
+ content = StringIO.new
328
+ while chunk = yield(RW_CHUNK_SIZE)
329
+ content << chunk
330
+ end
331
+ headers = { 'Content-MD5'=>Digest::MD5.hexdigest(content.string), 'Content-Type'=>'application/octet-stream', 'User-Agent'=>"Buildr-#{Buildr::VERSION}" }
332
+ request = Net::HTTP::Put.new(request_uri.empty? ? '/' : request_uri, headers)
333
+ request.basic_auth URI.decode(self.user), URI.decode(self.password) if self.user
334
+ response = nil
335
+ with_progress_bar options[:progress], path.split('/').last, content.size do |progress|
336
+ request.content_length = content.size
337
+ content.rewind
338
+ stream = Object.new
339
+ class << stream ; self ;end.send :define_method, :read do |*args|
340
+ bytes = content.read(*args)
341
+ progress << bytes if bytes
342
+ bytes
343
+ end
344
+ request.body_stream = stream
345
+ response = http.request(request)
346
+ end
347
+
348
+ case response
349
+ when Net::HTTPRedirection
350
+ # Try to download from the new URI, handle relative redirects.
351
+ trace "Redirected to #{response['Location']}"
352
+ content.rewind
353
+ return (self + URI.parse(response['location'])).write_internal(options) { |bytes| content.read(bytes) }
354
+ when Net::HTTPSuccess
355
+ else
356
+ raise RuntimeError, "Failed to upload #{self}: #{response.message}"
357
+ end
358
+ end
359
+ end
360
+
361
+ def connect
362
+ if proxy = proxy_uri
363
+ proxy = URI.parse(proxy) if String === proxy
364
+ http = Net::HTTP.new(host, port, proxy.host, proxy.port, proxy.user, proxy.password)
365
+ else
366
+ http = Net::HTTP.new(host, port)
367
+ end
368
+ if self.instance_of? URI::HTTPS
369
+ require 'net/https'
370
+ http.use_ssl = true
371
+ end
372
+ yield http
373
+ end
374
+ end
375
+
376
+ # File URL. Keep in mind that file URLs take the form of <code>file://host/path</code>, although the host
377
+ # is not used, so typically all you will see are three backslashes. This methods accept common variants,
378
+ # like <code>file:/path</code> but always returns a valid URL.
379
+ class FILE < Generic
380
+ COMPONENT = [ :host, :path ].freeze
381
+
382
+ def upload(source, options = nil)
383
+ super
384
+ if ::File === source then
385
+ ::File.chmod(source.stat.mode, real_path)
386
+ end
387
+ end
388
+
389
+ def initialize(*args)
390
+ super
391
+ # file:something (opaque) becomes file:///something
392
+ if path.nil?
393
+ set_path "/#{opaque}"
394
+ unless opaque.nil?
395
+ set_opaque nil
396
+ warn "#{caller[2]}: We'll accept this URL, but just so you know, it needs three slashes, as in: #{to_s}"
397
+ end
398
+ end
399
+ # Sadly, file://something really means file://something/ (something being server)
400
+ set_path '/' if path.empty?
401
+
402
+ # On windows, file://c:/something is not a valid URL, but people do it anyway, so if we see a drive-as-host,
403
+ # we'll just be nice enough to fix it. (URI actually strips the colon here)
404
+ if host =~ /^[a-zA-Z]$/
405
+ set_path "/#{host}:#{path}"
406
+ set_host nil
407
+ end
408
+ end
409
+
410
+ # See URI::Generic#read
411
+ def read(options = nil, &block)
412
+ options ||= {}
413
+ raise ArgumentError, 'Either you\'re attempting to read a file from another host (which we don\'t support), or you used two slashes by mistake, where you should have file:///<path>.' if host
414
+
415
+ path = real_path
416
+ # TODO: complain about clunky URLs
417
+ raise NotFoundError, "Looking for #{self} and can't find it." unless ::File.exists?(path)
418
+ raise NotFoundError, "Looking for the file #{self}, and it happens to be a directory." if ::File.directory?(path)
419
+ ::File.open path, 'rb' do |input|
420
+ with_progress_bar options[:progress], path.split('/').last, input.stat.size do |progress|
421
+ block ? block.call(input.read) : input.read
422
+ end
423
+ end
424
+ end
425
+
426
+ def to_s
427
+ "file://#{host}#{path}"
428
+ end
429
+
430
+ # Returns the file system path based that corresponds to the URL path.
431
+ # On all platforms this method unescapes the URL path.
432
+ def real_path #:nodoc:
433
+ CGI.unescape(path)
434
+ end
435
+
436
+ protected
437
+
438
+ def write_internal(options, &block) #:nodoc:
439
+ raise ArgumentError, 'Either you\'re attempting to write a file to another host (which we don\'t support), or you used two slashes by mistake, where you should have file:///<path>.' if host
440
+ temp = Tempfile.new(::File.basename(path))
441
+ temp.binmode
442
+ with_progress_bar options[:progress] && options[:size], path.split('/').last, options[:size] || 0 do |progress|
443
+ while chunk = yield(RW_CHUNK_SIZE)
444
+ temp.write chunk
445
+ progress << chunk
446
+ end
447
+ end
448
+ temp.close
449
+ mkpath ::File.dirname(real_path)
450
+ mv temp.path, real_path
451
+ real_path
452
+ end
453
+
454
+ @@schemes['FILE'] = FILE
455
+ end
456
+ end