buildr 1.3.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. data/CHANGELOG +66 -4
  2. data/{README → README.rdoc} +29 -16
  3. data/Rakefile +16 -20
  4. data/_buildr +38 -0
  5. data/addon/buildr/cobertura.rb +49 -45
  6. data/addon/buildr/emma.rb +238 -0
  7. data/addon/buildr/jetty.rb +1 -1
  8. data/addon/buildr/nailgun.rb +585 -661
  9. data/{lib/buildr/java → addon/buildr}/org/apache/buildr/BuildrNail$Main.class +0 -0
  10. data/{lib/buildr/java → addon/buildr}/org/apache/buildr/BuildrNail.class +0 -0
  11. data/{lib/buildr/java → addon/buildr}/org/apache/buildr/BuildrNail.java +0 -0
  12. data/bin/buildr +9 -2
  13. data/buildr.buildfile +53 -0
  14. data/buildr.gemspec +21 -14
  15. data/doc/css/default.css +51 -48
  16. data/doc/css/print.css +60 -55
  17. data/doc/images/favicon.png +0 -0
  18. data/doc/images/growl-icon.tiff +0 -0
  19. data/doc/images/project-structure.png +0 -0
  20. data/doc/pages/artifacts.textile +46 -156
  21. data/doc/pages/building.textile +63 -323
  22. data/doc/pages/contributing.textile +112 -102
  23. data/doc/pages/download.textile +19 -27
  24. data/doc/pages/extending.textile +27 -81
  25. data/doc/pages/getting_started.textile +44 -119
  26. data/doc/pages/index.textile +26 -47
  27. data/doc/pages/languages.textile +407 -0
  28. data/doc/pages/more_stuff.textile +92 -173
  29. data/doc/pages/packaging.textile +71 -239
  30. data/doc/pages/projects.textile +58 -233
  31. data/doc/pages/recipes.textile +19 -43
  32. data/doc/pages/settings_profiles.textile +39 -104
  33. data/doc/pages/testing.textile +41 -304
  34. data/doc/pages/troubleshooting.textile +29 -47
  35. data/doc/pages/whats_new.textile +69 -167
  36. data/doc/print.haml +0 -1
  37. data/doc/print.toc.yaml +1 -0
  38. data/doc/scripts/buildr-git.rb +1 -1
  39. data/doc/site.haml +1 -0
  40. data/doc/site.toc.yaml +8 -5
  41. data/{KEYS → etc/KEYS} +0 -0
  42. data/etc/git-svn-authors +16 -0
  43. data/lib/buildr.rb +2 -5
  44. data/lib/buildr/core/application.rb +192 -98
  45. data/lib/buildr/core/build.rb +140 -91
  46. data/lib/buildr/core/checks.rb +5 -5
  47. data/lib/buildr/core/common.rb +1 -1
  48. data/lib/buildr/core/compile.rb +12 -10
  49. data/lib/buildr/core/filter.rb +151 -46
  50. data/lib/buildr/core/generate.rb +9 -9
  51. data/lib/buildr/core/progressbar.rb +1 -1
  52. data/lib/buildr/core/project.rb +8 -7
  53. data/lib/buildr/core/test.rb +51 -26
  54. data/lib/buildr/core/transports.rb +22 -38
  55. data/lib/buildr/core/util.rb +78 -26
  56. data/lib/buildr/groovy.rb +18 -0
  57. data/lib/buildr/groovy/bdd.rb +105 -0
  58. data/lib/buildr/groovy/compiler.rb +138 -0
  59. data/lib/buildr/ide/eclipse.rb +102 -71
  60. data/lib/buildr/ide/idea.rb +7 -12
  61. data/lib/buildr/ide/idea7x.rb +7 -8
  62. data/lib/buildr/java.rb +4 -7
  63. data/lib/buildr/java/ant.rb +26 -5
  64. data/lib/buildr/java/bdd.rb +449 -0
  65. data/lib/buildr/java/commands.rb +9 -9
  66. data/lib/buildr/java/{compilers.rb → compiler.rb} +8 -90
  67. data/lib/buildr/java/jruby.rb +29 -11
  68. data/lib/buildr/java/jtestr_runner.rb.erb +116 -0
  69. data/lib/buildr/java/packaging.rb +23 -16
  70. data/lib/buildr/java/pom.rb +1 -1
  71. data/lib/buildr/java/rjb.rb +21 -8
  72. data/lib/buildr/java/test_result.rb +308 -0
  73. data/lib/buildr/java/tests.rb +324 -0
  74. data/lib/buildr/packaging/artifact.rb +12 -11
  75. data/lib/buildr/packaging/artifact_namespace.rb +7 -4
  76. data/lib/buildr/packaging/gems.rb +3 -3
  77. data/lib/buildr/packaging/zip.rb +13 -10
  78. data/lib/buildr/resources/buildr.icns +0 -0
  79. data/lib/buildr/scala.rb +19 -0
  80. data/lib/buildr/scala/compiler.rb +109 -0
  81. data/lib/buildr/scala/tests.rb +203 -0
  82. data/rakelib/apache.rake +71 -45
  83. data/rakelib/doc.rake +2 -2
  84. data/rakelib/package.rake +3 -2
  85. data/rakelib/rspec.rake +23 -21
  86. data/rakelib/setup.rake +34 -9
  87. data/rakelib/stage.rake +4 -1
  88. data/spec/addon/cobertura_spec.rb +77 -0
  89. data/spec/addon/emma_spec.rb +120 -0
  90. data/spec/addon/test_coverage_spec.rb +255 -0
  91. data/spec/{application_spec.rb → core/application_spec.rb} +82 -4
  92. data/spec/{artifact_namespace_spec.rb → core/artifact_namespace_spec.rb} +12 -1
  93. data/spec/core/build_spec.rb +415 -0
  94. data/spec/{checks_spec.rb → core/checks_spec.rb} +2 -2
  95. data/spec/{common_spec.rb → core/common_spec.rb} +119 -30
  96. data/spec/{compile_spec.rb → core/compile_spec.rb} +17 -13
  97. data/spec/core/generate_spec.rb +33 -0
  98. data/spec/{project_spec.rb → core/project_spec.rb} +9 -6
  99. data/spec/{test_spec.rb → core/test_spec.rb} +222 -28
  100. data/spec/{transport_spec.rb → core/transport_spec.rb} +5 -9
  101. data/spec/groovy/bdd_spec.rb +80 -0
  102. data/spec/{groovy_compilers_spec.rb → groovy/compiler_spec.rb} +1 -1
  103. data/spec/ide/eclipse_spec.rb +243 -0
  104. data/spec/{java_spec.rb → java/ant.rb} +7 -17
  105. data/spec/java/bdd_spec.rb +358 -0
  106. data/spec/{java_compilers_spec.rb → java/compiler_spec.rb} +1 -1
  107. data/spec/java/java_spec.rb +88 -0
  108. data/spec/{java_packaging_spec.rb → java/packaging_spec.rb} +65 -4
  109. data/spec/{java_test_frameworks_spec.rb → java/tests_spec.rb} +31 -10
  110. data/spec/{archive_spec.rb → packaging/archive_spec.rb} +12 -2
  111. data/spec/{artifact_spec.rb → packaging/artifact_spec.rb} +12 -5
  112. data/spec/{packaging_helper.rb → packaging/packaging_helper.rb} +0 -0
  113. data/spec/{packaging_spec.rb → packaging/packaging_spec.rb} +1 -1
  114. data/spec/sandbox.rb +22 -5
  115. data/spec/{scala_compilers_spec.rb → scala/compiler_spec.rb} +1 -1
  116. data/spec/{scala_test_frameworks_spec.rb → scala/tests_spec.rb} +11 -12
  117. data/spec/spec_helpers.rb +38 -17
  118. metadata +103 -70
  119. data/lib/buildr/java/bdd_frameworks.rb +0 -265
  120. data/lib/buildr/java/groovyc.rb +0 -137
  121. data/lib/buildr/java/test_frameworks.rb +0 -450
  122. data/spec/build_spec.rb +0 -193
  123. data/spec/java_bdd_frameworks_spec.rb +0 -238
  124. data/spec/spec.opts +0 -6
@@ -50,8 +50,6 @@ module Buildr
50
50
  header = <<-EOF
51
51
  # Version number for this release
52
52
  VERSION_NUMBER = "1.0.0"
53
- # Version number for the next release
54
- NEXT_VERSION = "1.0.1"
55
53
  # Group identifier for your projects
56
54
  GROUP = "#{name}"
57
55
  COPYRIGHT = ""
@@ -150,13 +148,15 @@ EOF
150
148
 
151
149
  #get plugins configurations
152
150
  plugins = project['build'].first['plugins'].first['plugin'] rescue {}
153
- compile_plugin = plugins.find{|pl| (pl['groupId'].nil? or pl['groupId'].first == 'org.apache.maven.plugins') and pl['artifactId'].first == 'maven-compiler-plugin'}
154
- if compile_plugin
155
- source = compile_plugin.first['configuration'].first['source'] rescue nil
156
- target = compile_plugin.first['configuration'].first['target'] rescue nil
157
-
158
- script << " compile.options.source = '#{source}'" if source
159
- script << " compile.options.target = '#{target}'" if target
151
+ if plugins
152
+ compile_plugin = plugins.find{|pl| (pl['groupId'].nil? or pl['groupId'].first == 'org.apache.maven.plugins') and pl['artifactId'].first == 'maven-compiler-plugin'}
153
+ if compile_plugin
154
+ source = compile_plugin.first['configuration'].first['source'] rescue nil
155
+ target = compile_plugin.first['configuration'].first['target'] rescue nil
156
+
157
+ script << " compile.options.source = '#{source}'" if source
158
+ script << " compile.options.target = '#{target}'" if target
159
+ end
160
160
  end
161
161
 
162
162
  compile_dependencies = pom.dependencies
@@ -143,7 +143,7 @@ protected
143
143
  end
144
144
 
145
145
  def changed?
146
- return false unless @output
146
+ return false unless @output && Time.now - @last_time > 0.1
147
147
  return human(@count) != human(@previous) if @total == 0
148
148
  return true if (@count - @previous) >= @total / 100
149
149
  return Time.now - @last_time > 1
@@ -319,7 +319,7 @@ module Buildr
319
319
  def local_task(args, &block)
320
320
  task args do |task|
321
321
  local_projects do |project|
322
- puts block.call(project.name) if block && verbose
322
+ info block.call(project.name) if block
323
323
  task("#{project.name}:#{task.name}").invoke
324
324
  end
325
325
  end
@@ -337,12 +337,13 @@ module Buildr
337
337
 
338
338
  def local_projects(dir = nil, &block) #:nodoc:
339
339
  dir = File.expand_path(dir || Buildr.application.original_dir)
340
- projects = Project.projects.select { |project| project.base_dir == dir }
340
+ projects = @projects ? @projects.values : []
341
+ projects = projects.select { |project| project.base_dir == dir }
341
342
  if projects.empty? && dir != Dir.pwd && File.dirname(dir) != dir
342
343
  local_projects(File.dirname(dir), &block)
343
344
  elsif block
344
345
  if projects.empty?
345
- warn "No projects defined for directory #{Buildr.application.original_dir}" if verbose
346
+ warn "No projects defined for directory #{Buildr.application.original_dir}"
346
347
  else
347
348
  projects.each { |project| block[project] }
348
349
  end
@@ -514,8 +515,8 @@ module Buildr
514
515
  def task(*args, &block)
515
516
  task_name, arg_names, deps = Buildr.application.resolve_args(args)
516
517
  if task_name =~ /^:/
517
- Buildr.application.switch_to_namespace [] do
518
- task = Rake::Task.define_task(task_name[1..-1])
518
+ task = Buildr.application.switch_to_namespace [] do
519
+ Rake::Task.define_task(task_name[1..-1])
519
520
  end
520
521
  elsif Buildr.application.current_scope == name.split(':')
521
522
  task = Rake::Task.define_task(task_name)
@@ -867,7 +868,7 @@ module Buildr
867
868
  projects
868
869
  end
869
870
 
870
- desc "Freezes the Buildfile so it always uses Buildr version #{Buildr::VERSION}"
871
+ desc "Freeze the Buildfile so it always uses Buildr version #{Buildr::VERSION}"
871
872
  task 'freeze' do
872
873
  puts "Freezing the Buildfile so it always uses Buildr version #{Buildr::VERSION}"
873
874
  original = File.read(Buildr.application.buildfile)
@@ -879,7 +880,7 @@ module Buildr
879
880
  File.open(Buildr.application.buildfile, "w") { |file| file.write modified }
880
881
  end
881
882
 
882
- desc 'Unfreezes the Buildfile to use the latest version of Buildr'
883
+ desc 'Unfreeze the Buildfile to use the latest version of Buildr'
883
884
  task 'unfreeze' do
884
885
  puts 'Unfreezing the Buildfile to use the latest version of Buildr from your Gems repository.'
885
886
  modified = File.read(Buildr.application.buildfile).sub(/^\s*gem\s*(["'])buildr\1.*\n/, "")
@@ -24,7 +24,7 @@ module Buildr
24
24
  # The underlying test framework used by TestTask.
25
25
  # To add a new test framework, extend TestFramework::Base and add your framework using:
26
26
  # Buildr::TestFramework << MyFramework
27
- class TestFramework
27
+ module TestFramework
28
28
 
29
29
  class << self
30
30
 
@@ -82,10 +82,10 @@ module Buildr
82
82
  raise 'Not implemented'
83
83
  end
84
84
 
85
- # Returns a list of dependencies for this framework. Defaults to obtaining a list of
86
- # artifact specifications from the REQUIRES constant.
85
+ # Returns a list of dependencies for this framework. Default is an empty list,
86
+ # override to add dependencies.
87
87
  def dependencies
88
- @dependencies ||= FileList[*(const_get('REQUIRES') rescue [])]
88
+ @dependencies ||= []
89
89
  end
90
90
 
91
91
  end
@@ -159,7 +159,7 @@ module Buildr
159
159
  # !(foo ^ bar) tests for equality and accepts nil as false (and select is less obfuscated than reject on ^).
160
160
  projects = ([project] + project.projects).select { |project| !(project.test.options[:integration] ^ integration) }
161
161
  projects.each do |project|
162
- puts "Testing #{project.name}" if verbose
162
+ info "Testing #{project.name}"
163
163
  begin
164
164
  project.test.invoke
165
165
  rescue
@@ -179,20 +179,23 @@ module Buildr
179
179
  end
180
180
 
181
181
  # Default options already set on each test task.
182
- DEFAULT_OPTIONS = { :fail_on_failure=>true, :fork=>:once, :properties=>{}, :environment=>{} }
182
+ def default_options
183
+ { :fail_on_failure=>true, :fork=>:once, :properties=>{}, :environment=>{} }
184
+ end
183
185
 
184
186
  def initialize(*args) #:nodoc:
185
187
  super
186
188
  @dependencies = FileList[]
187
189
  @include = []
188
190
  @exclude = []
191
+ @forced_need = false
189
192
  parent_task = Project.parent_task(name)
190
193
  if parent_task.respond_to?(:options)
191
- @options = OpenObject.new { |hash, key| parent_task.options[key] }
194
+ @options = OpenObject.new { |hash, key| hash[key] = parent_task.options[key].clone rescue hash[key] = parent_task.options[key] }
192
195
  else
193
- @options = OpenObject.new(DEFAULT_OPTIONS)
196
+ @options = OpenObject.new(default_options)
194
197
  end
195
- enhance do
198
+ enhance [application.buildfile.name] do
196
199
  run_tests if framework
197
200
  end
198
201
  end
@@ -215,6 +218,10 @@ module Buildr
215
218
  end
216
219
 
217
220
  def execute(args) #:nodoc:
221
+ if Buildr.options.test == false
222
+ info "Skipping tests for #{project.name}"
223
+ return
224
+ end
218
225
  setup.invoke
219
226
  begin
220
227
  super
@@ -272,7 +279,7 @@ module Buildr
272
279
  # :call-seq:
273
280
  # with(*specs) => self
274
281
  #
275
- # Specify artifacts (specs, tasks, files, etc) to include in the depdenenciest list
282
+ # Specify artifacts (specs, tasks, files, etc) to include in the dependencies list
276
283
  # when compiling and running tests.
277
284
  def with(*artifacts)
278
285
  @dependencies |= Buildr.artifacts(artifacts.flatten).uniq
@@ -388,6 +395,16 @@ module Buildr
388
395
  @report_to ||= file(@project.path_to(:reports, framework)=>self)
389
396
  end
390
397
 
398
+ # The path to the file that stores the time stamp of the last successful test run.
399
+ def last_successful_run_file #:nodoc:
400
+ File.join(report_to.to_s, 'last_successful_run')
401
+ end
402
+
403
+ # The time stamp of the last successful test run. Or Rake::EARLY if no successful test run recorded.
404
+ def timestamp #:nodoc:
405
+ File.exist?(last_successful_run_file) ? File.mtime(last_successful_run_file) : Rake::EARLY
406
+ end
407
+
391
408
  # The project this task belongs to.
392
409
  attr_reader :project
393
410
 
@@ -424,20 +441,28 @@ module Buildr
424
441
  if @tests.empty?
425
442
  @passed_tests, @failed_tests = [], []
426
443
  else
427
- puts "Running tests in #{@project.name}" if verbose
444
+ info "Running tests in #{@project.name}"
428
445
  @passed_tests = @framework.run(@tests, dependencies)
429
446
  @failed_tests = @tests - @passed_tests
430
447
  unless @failed_tests.empty?
431
- warn "The following tests failed:\n#{@failed_tests.join("\n")}" if verbose
448
+ error "The following tests failed:\n#{@failed_tests.join("\n")}"
432
449
  fail 'Tests failed!'
433
450
  end
434
451
  end
452
+ record_successful_run unless @forced_need
435
453
  end
436
454
 
455
+ # Call this method when a test run is successful to record the current system time.
456
+ def record_successful_run #:nodoc:
457
+ mkdir_p report_to.to_s
458
+ touch last_successful_run_file
459
+ end
460
+
437
461
  # Limit running tests to specific list.
438
462
  def only_run(tests)
439
463
  @include = Array(tests)
440
464
  @exclude.clear
465
+ @forced_need = true
441
466
  end
442
467
 
443
468
  def invoke_prerequisites(args, chain) #:nodoc:
@@ -445,6 +470,14 @@ module Buildr
445
470
  super
446
471
  end
447
472
 
473
+ def needed? #:nodoc:
474
+ latest_prerequisite = @prerequisites.map { |p| application[p, @scope] }.max { |a,b| a.timestamp<=>b.timestamp }
475
+ needed = (timestamp == Rake::EARLY) || latest_prerequisite.timestamp > timestamp
476
+ trace "Testing#{needed ? ' ' : ' not '}needed. " +
477
+ "Latest prerequisite change: #{latest_prerequisite.timestamp} (#{latest_prerequisite.to_s}). " +
478
+ "Last successful test run: #{timestamp}."
479
+ return needed || @forced_need || Buildr.options.test == :all
480
+ end
448
481
  end
449
482
 
450
483
 
@@ -458,7 +491,7 @@ module Buildr
458
491
  @setup = task("#{name}:setup")
459
492
  @teardown = task("#{name}:teardown")
460
493
  enhance do
461
- puts 'Running integration tests...' if verbose
494
+ info 'Running integration tests...'
462
495
  TestTask.run_local_tests true
463
496
  end
464
497
  end
@@ -506,7 +539,7 @@ module Buildr
506
539
  # buildr test:MyTest
507
540
  # will run the test com.example.MyTest, if such a test exists for this project.
508
541
  #
509
- # If you want to run multiple test, separate tham with a comma. You can also use glob
542
+ # If you want to run multiple test, separate them with a comma. You can also use glob
510
543
  # (* and ?) patterns to match multiple tests, see the TestTask#include method.
511
544
  rule /^test:.*$/ do |task|
512
545
  # The map works around a JRuby bug whereby the string looks fine, but fails in fnmatch.
@@ -514,14 +547,6 @@ module Buildr
514
547
  task('test').invoke
515
548
  end
516
549
 
517
- task 'build' do |task|
518
- # Make sure this happens as the last action on the build, so all other enhancements
519
- # are made to run before starting the tests.
520
- task.enhance do
521
- task('test').invoke unless Buildr.options.test == false
522
- end
523
- end
524
-
525
550
  IntegrationTestsTask.define_task('integration')
526
551
 
527
552
  # Similar to test:[pattern] but for integration tests.
@@ -563,12 +588,12 @@ module Buildr
563
588
  test.with project.compile.dependencies
564
589
  # Picking up the test frameworks adds further dependencies.
565
590
  test.framework
591
+
592
+ project.build test unless test.options[:integration]
566
593
 
567
594
  project.clean do
568
- verbose(false) do
569
- rm_rf test.compile.target.to_s if test.compile.target
570
- rm_rf test.report_to.to_s
571
- end
595
+ rm_rf test.compile.target.to_s, :verbose=>false if test.compile.target
596
+ rm_rf test.report_to.to_s, :verbose=>false
572
597
  end
573
598
  end
574
599
 
@@ -18,8 +18,7 @@ require 'cgi'
18
18
  require 'net/http'
19
19
  require 'net/https'
20
20
  # PATCH: On Windows, Net::SSH 2.0.2 attempts to load the Pageant DLLs which break on JRuby.
21
- $LOAD_PATH << 'net/ssh/authentication/pageant' if RUBY_PLATFORM =~ /java/
22
- require 'net/ssh'
21
+ $LOADED_FEATURES << 'net/ssh/authentication/pageant.rb' if RUBY_PLATFORM =~ /java/
23
22
  require 'net/sftp'
24
23
  require 'uri'
25
24
  require 'digest/md5'
@@ -29,24 +28,6 @@ require 'tempfile'
29
28
  require 'buildr/core/progressbar'
30
29
 
31
30
 
32
- # Monkeypatching: SFTP never defines the mkdir method on its session or the underlying
33
- # driver, it just redirect calls through method_missing. Rake, on the other hand, decides
34
- # to define mkdir on Object, and so routes our calls to FileUtils.
35
- module Net #:nodoc:all
36
- class Session
37
- def mkdir(path, attrs = {})
38
- method_missing :mkdir, path, attrs
39
- end
40
- end
41
-
42
- class SFTP::Protocol::Driver
43
- def mkdir(first, path, attrs = {})
44
- method_missing :mkdir, first, path, attrs
45
- end
46
- end
47
- end
48
-
49
-
50
31
  # Not quite open-uri, but similar. Provides read and write methods for the resource represented by the URI.
51
32
  # Currently supports reads for URI::HTTP and writes for URI::SFTP. Also provides convenience methods for
52
33
  # downloads and uploads.
@@ -56,6 +37,9 @@ module URI
56
37
  class NotFoundError < RuntimeError
57
38
  end
58
39
 
40
+ # How many bytes to read/write at once.
41
+ RW_CHUNK_SIZE = 2 ** 20 #:nodoc:
42
+
59
43
  class << self
60
44
 
61
45
  # :call-seq:
@@ -292,7 +276,7 @@ module URI
292
276
  def read(options = nil, &block)
293
277
  options ||= {}
294
278
  connect do |http|
295
- puts "Requesting #{self}" if Buildr.application.options.trace
279
+ trace "Requesting #{self}"
296
280
  headers = { 'If-Modified-Since' => CGI.rfc1123_date(options[:modified].utc) } if options[:modified]
297
281
  request = Net::HTTP::Get.new(request_uri.empty? ? '/' : request_uri, headers)
298
282
  request.basic_auth self.user, self.password if self.user
@@ -300,14 +284,14 @@ module URI
300
284
  case response
301
285
  when Net::HTTPNotModified
302
286
  # No modification, nothing to do.
303
- puts 'Not modified since last download' if Buildr.application.options.trace
287
+ trace 'Not modified since last download'
304
288
  return nil
305
289
  when Net::HTTPRedirection
306
290
  # Try to download from the new URI, handle relative redirects.
307
- puts "Redirected to #{response['Location']}" if Buildr.application.options.trace
291
+ trace "Redirected to #{response['Location']}"
308
292
  return (self + URI.parse(response['location'])).read(options, &block)
309
293
  when Net::HTTPOK
310
- puts "Downloading #{self}" if verbose
294
+ info "Downloading #{self}"
311
295
  result = nil
312
296
  with_progress_bar options[:progress], path.split('/').last, response.content_length do |progress|
313
297
  if block
@@ -338,9 +322,9 @@ module URI
338
322
  def write_internal(options, &block) #:nodoc:
339
323
  options ||= {}
340
324
  connect do |http|
341
- puts "Uploading to #{path}" if Buildr.application.options.trace
325
+ trace "Uploading to #{path}"
342
326
  content = StringIO.new
343
- while chunk = yield(32 * 4096)
327
+ while chunk = yield(RW_CHUNK_SIZE)
344
328
  content << chunk
345
329
  end
346
330
  headers = { 'Content-MD5'=>Digest::MD5.hexdigest(content.string) }
@@ -363,7 +347,7 @@ module URI
363
347
  case response
364
348
  when Net::HTTPRedirection
365
349
  # Try to download from the new URI, handle relative redirects.
366
- puts "Redirected to #{response['Location']}" if Buildr.application.options.trace
350
+ trace "Redirected to #{response['Location']}"
367
351
  content.rewind
368
352
  return (self + URI.parse(response['location'])).write_internal(options) { |bytes| content.read(bytes) }
369
353
  when Net::HTTPSuccess
@@ -408,23 +392,23 @@ module URI
408
392
  ssh_options = { :port=>port, :password=>password }.merge(options[:ssh_options] || {})
409
393
  ssh_options[:password] ||= SFTP.passwords[host]
410
394
  begin
411
- puts "Connecting to #{host}" if Buildr.application.options.trace
395
+ trace "Connecting to #{host}"
412
396
  result = nil
413
397
  Net::SFTP.start(host, user, ssh_options) do |sftp|
414
398
  SFTP.passwords[host] = ssh_options[:password]
415
- puts 'connected' if Buildr.application.options.trace
399
+ trace 'connected'
416
400
 
417
401
  with_progress_bar options[:progress] && options[:size], path.split('/'), options[:size] || 0 do |progress|
418
- puts "Downloading to #{path}" if Buildr.application.options.trace
402
+ trace "Downloading to #{path}"
419
403
  sftp.file.open(path, 'r') do |file|
420
404
  if block
421
- while chunk = file.read(32 * 4096)
405
+ while chunk = file.read(RW_CHUNK_SIZE)
422
406
  block.call chunk
423
407
  progress << chunk
424
408
  end
425
409
  else
426
410
  result = ''
427
- while chunk = file.read(32 * 4096)
411
+ while chunk = file.read(RW_CHUNK_SIZE)
428
412
  result << chunk
429
413
  progress << chunk
430
414
  end
@@ -451,14 +435,14 @@ module URI
451
435
  ssh_options = { :port=>port, :password=>password }.merge(options[:ssh_options] || {})
452
436
  ssh_options[:password] ||= SFTP.passwords[host]
453
437
  begin
454
- puts "Connecting to #{host}" if Buildr.application.options.trace
438
+ trace "Connecting to #{host}"
455
439
  Net::SFTP.start(host, user, ssh_options) do |sftp|
456
440
  SFTP.passwords[host] = ssh_options[:password]
457
- puts 'connected' if Buildr.application.options.trace
441
+ trace 'Connected'
458
442
 
459
443
  # To create a path, we need to create all its parent. We use realpath to determine if
460
444
  # the path already exists, otherwise mkdir fails.
461
- puts "Creating path #{path}" if Buildr.application.options.trace
445
+ trace "Creating path #{path}"
462
446
  File.dirname(path).split('/').reject(&:empty?).inject('/') do |base, part|
463
447
  combined = base + part
464
448
  sftp.close(sftp.opendir!(combined)) rescue sftp.mkdir! combined, {}
@@ -466,9 +450,9 @@ module URI
466
450
  end
467
451
 
468
452
  with_progress_bar options[:progress] && options[:size], path.split('/'), options[:size] || 0 do |progress|
469
- puts "Uploading to #{path}" if Buildr.application.options.trace
453
+ trace "Uploading to #{path}"
470
454
  sftp.file.open(path, 'w') do |file|
471
- while chunk = yield(32 * 4096)
455
+ while chunk = yield(RW_CHUNK_SIZE)
472
456
  file.write chunk
473
457
  progress << chunk
474
458
  end
@@ -555,7 +539,7 @@ module URI
555
539
  Tempfile.open File.basename(path) do |temp|
556
540
  temp.binmode
557
541
  with_progress_bar options[:progress] && options[:size], path.split('/'), options[:size] || 0 do |progress|
558
- while chunk = yield(32 * 4096)
542
+ while chunk = yield(RW_CHUNK_SIZE)
559
543
  temp.write chunk
560
544
  progress << chunk
561
545
  end
@@ -108,36 +108,77 @@ module Buildr
108
108
  FileList[dirs.map { |dir| File.join(dir, '/**/{*,.*}') }].reject { |file| File.basename(file) =~ /^[.]{1,2}$/ }
109
109
  end
110
110
 
111
- end
112
- end
111
+ # Utility methods for running gem commands
112
+ module Gems
113
+ extend self
114
+
115
+ # Install gems specified by each Gem::Dependency if they are missing. This method prompts the user
116
+ # for permission before installing anything.
117
+ #
118
+ # Returns the installed Gem::Dependency objects or fails if permission not granted or when buildr
119
+ # is not running interactively (on a tty)
120
+ def install(*dependencies)
121
+ raise ArgumentError, "Expected at least one argument" if dependencies.empty?
122
+ remote = dependencies.map { |dep| Gem::SourceInfoCache.search(dep).last || dep }
123
+ not_found_deps, to_install = remote.partition { |gem| gem.is_a?(Gem::Dependency) }
124
+ fail Gem::LoadError, "Build requires the gems #{not_found_deps.join(', ')}, which cannot be found in local or remote repository." unless not_found_deps.empty?
125
+ uses = "This build requires the gems #{to_install.map(&:full_name).join(', ')}:"
126
+ fail Gem::LoadError, "#{uses} to install, run Buildr interactively." unless $stdout.isatty
127
+ unless agree("#{uses} do you want me to install them? [Y/n]", true)
128
+ fail Gem::LoadError, 'Cannot build without these gems.'
129
+ end
130
+ to_install.each do |spec|
131
+ say "Installing #{spec.full_name} ... " if verbose
132
+ command 'install', spec.name, '-v', spec.version.to_s, :verbose => false
133
+ Gem.source_index.load_gems_in Gem::SourceIndex.installed_spec_directories
134
+ end
135
+ to_install
136
+ end
113
137
 
138
+ # Execute a GemRunner command
139
+ def command(cmd, *args)
140
+ options = Hash === args.last ? args.pop : {}
141
+ gem_home = ENV['GEM_HOME'] || Gem.path.find { |f| File.writable?(f) }
142
+ options[:sudo] = :root unless Util.win_os? || gem_home
143
+ options[:command] = 'gem'
144
+ args << options
145
+ args.unshift '-i', gem_home if cmd == 'install' && gem_home && !args.any?{ |a| a[/-i|--install-dir/] }
146
+ Util.ruby cmd, *args
147
+ end
114
148
 
115
- module Kernel #:nodoc:
116
- # Borrowed from Ruby 1.9.
117
- def tap
118
- yield self if block_given?
119
- self
120
- end unless method_defined?('tap')
149
+ end # Gems
150
+
151
+ end # Util
121
152
  end
122
153
 
123
154
 
124
- class Symbol #:nodoc:
125
- # Borrowed from Ruby 1.9.
126
- def to_proc
127
- Proc.new{|*args| args.shift.__send__(self, *args)}
128
- end unless method_defined?('to_proc')
129
- end
155
+ if RUBY_VERSION < '1.9.0'
156
+ module Kernel #:nodoc:
157
+ # Borrowed from Ruby 1.9.
158
+ def tap
159
+ yield self if block_given?
160
+ self
161
+ end unless method_defined?('tap')
162
+ end
130
163
 
131
164
 
132
- # Also borrowed from Ruby 1.9.
133
- class BasicObject #:nodoc:
134
- (instance_methods - ['__send__', '__id__', '==', 'send', 'send!', 'respond_to?', 'equal?', 'object_id']).
135
- each do |method|
136
- undef_method method
137
- end
165
+ class Symbol #:nodoc:
166
+ # Borrowed from Ruby 1.9.
167
+ def to_proc
168
+ Proc.new{|*args| args.shift.__send__(self, *args)}
169
+ end unless method_defined?('to_proc')
170
+ end
171
+
172
+ # Also borrowed from Ruby 1.9.
173
+ class BasicObject #:nodoc:
174
+ (instance_methods - ['__send__', '__id__', '==', 'send', 'send!', 'respond_to?', 'equal?', 'object_id']).
175
+ each do |method|
176
+ undef_method method
177
+ end
138
178
 
139
- def self.ancestors
140
- [Kernel]
179
+ def self.ancestors
180
+ [Kernel]
181
+ end
141
182
  end
142
183
  end
143
184
 
@@ -187,10 +228,21 @@ class Hash
187
228
  # Hash.from_properties(str)
188
229
  # => { 'foo'=>'bar', 'baz'=>'fab' }.to_properties
189
230
  def from_java_properties(string)
190
- string.gsub(/\\\n/, '').split("\n").select { |line| line =~ /^[^#].*=.*/ }.
191
- map { |line| line.gsub(/\\[trnf\\]/) { |escaped| {?t=>"\t", ?r=>"\r", ?n=>"\n", ?f=>"\f", ?\\=>"\\"}[escaped[1]] } }.
192
- map { |line| line.split('=') }.
193
- inject({}) { |hash, (name, value)| hash.merge(name=>value) }
231
+ hash = {}
232
+ input_stream = Java.java.io.StringBufferInputStream.new(string)
233
+ java_properties = Java.java.util.Properties.new
234
+ java_properties.load input_stream
235
+ keys = java_properties.keySet.iterator
236
+ while keys.hasNext
237
+ # Calling key.next in JRuby returns a java.lang.String, behaving as a Ruby string and life is good.
238
+ # MRI, unfortunately, treats next() like the interface says returning an object that's not a String,
239
+ # and the Hash doesn't work the way we need it to. Unfortunately, we can call toString on MRI's object,
240
+ # but not on the JRuby one; calling to_s on the JRuby object returns what we need, but ... you guessed it.
241
+ # So this seems like the one hack to unite them both.
242
+ key = Java.java.lang.String.valueOf(keys.next)
243
+ hash[key] = java_properties.getProperty(key)
244
+ end
245
+ hash
194
246
  end
195
247
 
196
248
  end