mguymon-buildr 1.4.5-java

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.
Files changed (220) hide show
  1. data/CHANGELOG +1291 -0
  2. data/LICENSE +176 -0
  3. data/NOTICE +26 -0
  4. data/README.rdoc +134 -0
  5. data/Rakefile +44 -0
  6. data/_buildr +35 -0
  7. data/_jbuildr +35 -0
  8. data/addon/buildr/antlr.rb +65 -0
  9. data/addon/buildr/bnd.rb +147 -0
  10. data/addon/buildr/cobertura.rb +22 -0
  11. data/addon/buildr/drb.rb +281 -0
  12. data/addon/buildr/emma.rb +22 -0
  13. data/addon/buildr/hibernate.rb +149 -0
  14. data/addon/buildr/javacc.rb +85 -0
  15. data/addon/buildr/jaxb_xjc.rb +72 -0
  16. data/addon/buildr/jdepend.rb +60 -0
  17. data/addon/buildr/jetty.rb +248 -0
  18. data/addon/buildr/jibx.rb +86 -0
  19. data/addon/buildr/nailgun.rb +221 -0
  20. data/addon/buildr/openjpa.rb +88 -0
  21. data/addon/buildr/org/apache/buildr/BuildrNail$Main.class +0 -0
  22. data/addon/buildr/org/apache/buildr/BuildrNail.class +0 -0
  23. data/addon/buildr/org/apache/buildr/BuildrNail.java +41 -0
  24. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  25. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  26. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  27. data/addon/buildr/org/apache/buildr/JettyWrapper.java +144 -0
  28. data/addon/buildr/protobuf.rb +88 -0
  29. data/addon/buildr/xmlbeans.rb +93 -0
  30. data/bin/buildr +19 -0
  31. data/buildr.buildfile +58 -0
  32. data/buildr.gemspec +78 -0
  33. data/doc/_config.yml +1 -0
  34. data/doc/_layouts/default.html +90 -0
  35. data/doc/_layouts/preface.html +22 -0
  36. data/doc/artifacts.textile +217 -0
  37. data/doc/building.textile +276 -0
  38. data/doc/contributing.textile +268 -0
  39. data/doc/css/default.css +236 -0
  40. data/doc/css/print.css +101 -0
  41. data/doc/css/syntax.css +23 -0
  42. data/doc/download.textile +151 -0
  43. data/doc/extending.textile +212 -0
  44. data/doc/images/1442160941-frontcover.jpg +0 -0
  45. data/doc/images/asf-logo.gif +0 -0
  46. data/doc/images/asf-logo.png +0 -0
  47. data/doc/images/buildr-hires.png +0 -0
  48. data/doc/images/buildr.png +0 -0
  49. data/doc/images/favicon.png +0 -0
  50. data/doc/images/growl-icon.tiff +0 -0
  51. data/doc/images/note.png +0 -0
  52. data/doc/images/project-structure.png +0 -0
  53. data/doc/images/tip.png +0 -0
  54. data/doc/images/zbuildr.png +0 -0
  55. data/doc/images/zbuildr.tif +0 -0
  56. data/doc/index.textile +109 -0
  57. data/doc/installing.textile +284 -0
  58. data/doc/languages.textile +599 -0
  59. data/doc/mailing_lists.textile +29 -0
  60. data/doc/more_stuff.textile +845 -0
  61. data/doc/packaging.textile +618 -0
  62. data/doc/preface.textile +54 -0
  63. data/doc/projects.textile +276 -0
  64. data/doc/quick_start.textile +210 -0
  65. data/doc/releasing.textile +117 -0
  66. data/doc/scripts/buildr-git.rb +512 -0
  67. data/doc/scripts/gitflow.rb +296 -0
  68. data/doc/scripts/install-jruby.sh +44 -0
  69. data/doc/scripts/install-linux.sh +73 -0
  70. data/doc/scripts/install-osx.sh +52 -0
  71. data/doc/settings_profiles.textile +287 -0
  72. data/doc/testing.textile +247 -0
  73. data/etc/KEYS +189 -0
  74. data/lib/buildr.rb +44 -0
  75. data/lib/buildr/clojure.rb +34 -0
  76. data/lib/buildr/clojure/shell.rb +52 -0
  77. data/lib/buildr/core.rb +34 -0
  78. data/lib/buildr/core/application.rb +700 -0
  79. data/lib/buildr/core/build.rb +516 -0
  80. data/lib/buildr/core/cc.rb +166 -0
  81. data/lib/buildr/core/checks.rb +253 -0
  82. data/lib/buildr/core/common.rb +151 -0
  83. data/lib/buildr/core/compile.rb +622 -0
  84. data/lib/buildr/core/doc.rb +276 -0
  85. data/lib/buildr/core/environment.rb +129 -0
  86. data/lib/buildr/core/filter.rb +404 -0
  87. data/lib/buildr/core/generate.rb +197 -0
  88. data/lib/buildr/core/help.rb +119 -0
  89. data/lib/buildr/core/jrebel.rb +42 -0
  90. data/lib/buildr/core/linux.rb +30 -0
  91. data/lib/buildr/core/osx.rb +46 -0
  92. data/lib/buildr/core/progressbar.rb +161 -0
  93. data/lib/buildr/core/project.rb +975 -0
  94. data/lib/buildr/core/run.rb +43 -0
  95. data/lib/buildr/core/shell.rb +137 -0
  96. data/lib/buildr/core/test.rb +843 -0
  97. data/lib/buildr/core/transports.rb +575 -0
  98. data/lib/buildr/core/util.rb +537 -0
  99. data/lib/buildr/groovy.rb +20 -0
  100. data/lib/buildr/groovy/bdd.rb +106 -0
  101. data/lib/buildr/groovy/compiler.rb +153 -0
  102. data/lib/buildr/groovy/doc.rb +76 -0
  103. data/lib/buildr/groovy/shell.rb +57 -0
  104. data/lib/buildr/ide.rb +19 -0
  105. data/lib/buildr/ide/eclipse.rb +427 -0
  106. data/lib/buildr/ide/eclipse/java.rb +53 -0
  107. data/lib/buildr/ide/eclipse/plugin.rb +71 -0
  108. data/lib/buildr/ide/eclipse/scala.rb +68 -0
  109. data/lib/buildr/ide/idea.rb +576 -0
  110. data/lib/buildr/java.rb +25 -0
  111. data/lib/buildr/java/ant.rb +94 -0
  112. data/lib/buildr/java/bdd.rb +460 -0
  113. data/lib/buildr/java/cobertura.rb +297 -0
  114. data/lib/buildr/java/commands.rb +223 -0
  115. data/lib/buildr/java/compiler.rb +135 -0
  116. data/lib/buildr/java/deprecated.rb +141 -0
  117. data/lib/buildr/java/doc.rb +86 -0
  118. data/lib/buildr/java/ecj.rb +69 -0
  119. data/lib/buildr/java/emma.rb +244 -0
  120. data/lib/buildr/java/external.rb +73 -0
  121. data/lib/buildr/java/jruby.rb +122 -0
  122. data/lib/buildr/java/jtestr_result.rb +295 -0
  123. data/lib/buildr/java/jtestr_runner.rb.erb +116 -0
  124. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  125. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +142 -0
  126. data/lib/buildr/java/packaging.rb +734 -0
  127. data/lib/buildr/java/pom.rb +178 -0
  128. data/lib/buildr/java/rjb.rb +154 -0
  129. data/lib/buildr/java/test_result.rb +101 -0
  130. data/lib/buildr/java/tests.rb +362 -0
  131. data/lib/buildr/java/version_requirement.rb +172 -0
  132. data/lib/buildr/packaging.rb +25 -0
  133. data/lib/buildr/packaging/archive.rb +535 -0
  134. data/lib/buildr/packaging/artifact.rb +904 -0
  135. data/lib/buildr/packaging/artifact_namespace.rb +984 -0
  136. data/lib/buildr/packaging/artifact_search.rb +140 -0
  137. data/lib/buildr/packaging/gems.rb +105 -0
  138. data/lib/buildr/packaging/package.rb +249 -0
  139. data/lib/buildr/packaging/repository_array.rb +108 -0
  140. data/lib/buildr/packaging/tar.rb +189 -0
  141. data/lib/buildr/packaging/version_requirement.rb +192 -0
  142. data/lib/buildr/packaging/zip.rb +178 -0
  143. data/lib/buildr/packaging/ziptask.rb +356 -0
  144. data/lib/buildr/resources/buildr.icns +0 -0
  145. data/lib/buildr/resources/completed.png +0 -0
  146. data/lib/buildr/resources/failed.png +0 -0
  147. data/lib/buildr/resources/icons-license.txt +17 -0
  148. data/lib/buildr/run.rb +195 -0
  149. data/lib/buildr/scala.rb +26 -0
  150. data/lib/buildr/scala/bdd.rb +118 -0
  151. data/lib/buildr/scala/compiler.rb +242 -0
  152. data/lib/buildr/scala/doc.rb +142 -0
  153. data/lib/buildr/scala/org/apache/buildr/SpecsSingletonRunner.class +0 -0
  154. data/lib/buildr/scala/org/apache/buildr/SpecsSingletonRunner.java +57 -0
  155. data/lib/buildr/scala/shell.rb +52 -0
  156. data/lib/buildr/scala/tests.rb +171 -0
  157. data/lib/buildr/shell.rb +185 -0
  158. data/lib/buildr/version.rb +18 -0
  159. data/rakelib/all-in-one.rake +113 -0
  160. data/rakelib/checks.rake +57 -0
  161. data/rakelib/doc.rake +137 -0
  162. data/rakelib/metrics.rake +39 -0
  163. data/rakelib/package.rake +73 -0
  164. data/rakelib/release.rake +160 -0
  165. data/rakelib/rspec.rake +91 -0
  166. data/rakelib/setup.rake +66 -0
  167. data/rakelib/stage.rake +220 -0
  168. data/spec/addon/bnd_spec.rb +330 -0
  169. data/spec/addon/drb_spec.rb +328 -0
  170. data/spec/addon/jaxb_xjc_spec.rb +125 -0
  171. data/spec/core/application_spec.rb +631 -0
  172. data/spec/core/build_spec.rb +837 -0
  173. data/spec/core/cc_spec.rb +224 -0
  174. data/spec/core/checks_spec.rb +519 -0
  175. data/spec/core/common_spec.rb +725 -0
  176. data/spec/core/compile_spec.rb +658 -0
  177. data/spec/core/doc_spec.rb +195 -0
  178. data/spec/core/extension_spec.rb +201 -0
  179. data/spec/core/generate_spec.rb +33 -0
  180. data/spec/core/project_spec.rb +772 -0
  181. data/spec/core/run_spec.rb +93 -0
  182. data/spec/core/shell_spec.rb +146 -0
  183. data/spec/core/test_spec.rb +1320 -0
  184. data/spec/core/transport_spec.rb +544 -0
  185. data/spec/core/util_spec.rb +141 -0
  186. data/spec/groovy/bdd_spec.rb +80 -0
  187. data/spec/groovy/compiler_spec.rb +251 -0
  188. data/spec/groovy/doc_spec.rb +65 -0
  189. data/spec/ide/eclipse_spec.rb +739 -0
  190. data/spec/ide/idea_spec.rb +1145 -0
  191. data/spec/java/ant_spec.rb +37 -0
  192. data/spec/java/bdd_spec.rb +374 -0
  193. data/spec/java/cobertura_spec.rb +112 -0
  194. data/spec/java/commands_spec.rb +93 -0
  195. data/spec/java/compiler_spec.rb +252 -0
  196. data/spec/java/doc_spec.rb +56 -0
  197. data/spec/java/ecj_spec.rb +115 -0
  198. data/spec/java/emma_spec.rb +121 -0
  199. data/spec/java/external_spec.rb +56 -0
  200. data/spec/java/java_spec.rb +132 -0
  201. data/spec/java/packaging_spec.rb +1266 -0
  202. data/spec/java/run_spec.rb +78 -0
  203. data/spec/java/test_coverage_helper.rb +257 -0
  204. data/spec/java/tests_spec.rb +497 -0
  205. data/spec/packaging/archive_spec.rb +775 -0
  206. data/spec/packaging/artifact_namespace_spec.rb +743 -0
  207. data/spec/packaging/artifact_spec.rb +1074 -0
  208. data/spec/packaging/packaging_helper.rb +63 -0
  209. data/spec/packaging/packaging_spec.rb +719 -0
  210. data/spec/packaging/repository_array_spec.rb +109 -0
  211. data/spec/sandbox.rb +165 -0
  212. data/spec/scala/bdd_spec.rb +124 -0
  213. data/spec/scala/compiler_spec.rb +289 -0
  214. data/spec/scala/doc_spec.rb +88 -0
  215. data/spec/scala/scala.rb +38 -0
  216. data/spec/scala/tests_spec.rb +283 -0
  217. data/spec/spec_helpers.rb +369 -0
  218. data/spec/version_requirement_spec.rb +143 -0
  219. data/spec/xpath_matchers.rb +121 -0
  220. metadata +600 -0
@@ -0,0 +1,575 @@
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
+
17
+ require 'uri'
18
+ require 'net/http'
19
+ # PATCH: On Windows, Net::SSH 2.0.2 attempts to load the Pageant DLLs which break on JRuby.
20
+ $LOADED_FEATURES << 'net/ssh/authentication/pageant.rb' if RUBY_PLATFORM =~ /java/
21
+ gem 'net-ssh' ; Net.autoload :SSH, 'net/ssh'
22
+ gem 'net-sftp' ; Net.autoload :SFTP, 'net/sftp'
23
+ autoload :CGI, 'cgi'
24
+ require 'digest/md5'
25
+ require 'digest/sha1'
26
+ require 'stringio'
27
+ autoload :ProgressBar, 'buildr/core/progressbar'
28
+
29
+
30
+ # Not quite open-uri, but similar. Provides read and write methods for the resource represented by the URI.
31
+ # Currently supports reads for URI::HTTP and writes for URI::SFTP. Also provides convenience methods for
32
+ # downloads and uploads.
33
+ module URI
34
+
35
+ # Raised when trying to read/download a resource that doesn't exist.
36
+ class NotFoundError < RuntimeError
37
+ end
38
+
39
+ # How many bytes to read/write at once. Do not change without checking BUILDR-214 first.
40
+ RW_CHUNK_SIZE = 128 * 1024 #:nodoc:
41
+
42
+ class << self
43
+
44
+ # :call-seq:
45
+ # read(uri, options?) => content
46
+ # read(uri, options?) { |chunk| ... }
47
+ #
48
+ # Reads from the resource behind this URI. The first form returns the content of the resource,
49
+ # the second form yields to the block with each chunk of content (usually more than one).
50
+ #
51
+ # For example:
52
+ # File.open 'image.jpg', 'w' do |file|
53
+ # URI.read('http://example.com/image.jpg') { |chunk| file.write chunk }
54
+ # end
55
+ # Shorter version:
56
+ # File.open('image.jpg', 'w') { |file| file.write URI.read('http://example.com/image.jpg') }
57
+ #
58
+ # Supported options:
59
+ # * :modified -- Only download if file modified since this timestamp. Returns nil if not modified.
60
+ # * :progress -- Show the progress bar while reading.
61
+ def read(uri, options = nil, &block)
62
+ uri = URI.parse(uri.to_s) unless URI === uri
63
+ uri.read options, &block
64
+ end
65
+
66
+ # :call-seq:
67
+ # download(uri, target, options?)
68
+ #
69
+ # Downloads the resource to the target.
70
+ #
71
+ # The target may be a file name (string or task), in which case the file is created from the resource.
72
+ # The target may also be any object that responds to +write+, e.g. File, StringIO, Pipe.
73
+ #
74
+ # Use the progress bar when running in verbose mode.
75
+ def download(uri, target, options = nil)
76
+ uri = URI.parse(uri.to_s) unless URI === uri
77
+ uri.download target, options
78
+ end
79
+
80
+ # :call-seq:
81
+ # write(uri, content, options?)
82
+ # write(uri, options?) { |bytes| .. }
83
+ #
84
+ # Writes to the resource behind the URI. The first form writes the content from a string or an object
85
+ # that responds to +read+ and optionally +size+. The second form writes the content by yielding to the
86
+ # block. Each yield should return up to the specified number of bytes, the last yield returns nil.
87
+ #
88
+ # For example:
89
+ # File.open 'killer-app.jar', 'rb' do |file|
90
+ # write('sftp://localhost/jars/killer-app.jar') { |chunk| file.read(chunk) }
91
+ # end
92
+ # Or:
93
+ # write 'sftp://localhost/jars/killer-app.jar', File.read('killer-app.jar')
94
+ #
95
+ # Supported options:
96
+ # * :progress -- Show the progress bar while reading.
97
+ def write(uri, *args, &block)
98
+ uri = URI.parse(uri.to_s) unless URI === uri
99
+ uri.write *args, &block
100
+ end
101
+
102
+ # :call-seq:
103
+ # upload(uri, source, options?)
104
+ #
105
+ # Uploads from source to the resource.
106
+ #
107
+ # The source may be a file name (string or task), in which case the file is uploaded to the resource.
108
+ # The source may also be any object that responds to +read+ (and optionally +size+), e.g. File, StringIO, Pipe.
109
+ #
110
+ # Use the progress bar when running in verbose mode.
111
+ def upload(uri, source, options = nil)
112
+ uri = URI.parse(uri.to_s) unless URI === uri
113
+ uri.upload source, options
114
+ end
115
+
116
+ end
117
+
118
+ class Generic
119
+
120
+ # :call-seq:
121
+ # read(options?) => content
122
+ # read(options?) { |chunk| ... }
123
+ #
124
+ # Reads from the resource behind this URI. The first form returns the content of the resource,
125
+ # the second form yields to the block with each chunk of content (usually more than one).
126
+ #
127
+ # For options, see URI::read.
128
+ def read(options = nil, &block)
129
+ fail 'This protocol doesn\'t support reading (yet, how about helping by implementing it?)'
130
+ end
131
+
132
+ # :call-seq:
133
+ # download(target, options?)
134
+ #
135
+ # Downloads the resource to the target.
136
+ #
137
+ # The target may be a file name (string or task), in which case the file is created from the resource.
138
+ # The target may also be any object that responds to +write+, e.g. File, StringIO, Pipe.
139
+ #
140
+ # Use the progress bar when running in verbose mode.
141
+ def download(target, options = nil)
142
+ case target
143
+ when Rake::Task
144
+ download target.name, options
145
+ when String
146
+ # If download breaks we end up with a partial file which is
147
+ # worse than not having a file at all, so download to temporary
148
+ # file and then move over.
149
+ modified = File.stat(target).mtime if File.exist?(target)
150
+ temp = Tempfile.new(File.basename(target))
151
+ temp.binmode
152
+ read({:progress=>verbose}.merge(options || {}).merge(:modified=>modified)) { |chunk| temp.write chunk }
153
+ temp.close
154
+ mkpath File.dirname(target)
155
+ mv temp.path, target
156
+ when File
157
+ read({:progress=>verbose}.merge(options || {}).merge(:modified=>target.mtime)) { |chunk| target.write chunk }
158
+ target.flush
159
+ else
160
+ 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)
161
+ read({:progress=>verbose}.merge(options || {})) { |chunk| target.write chunk }
162
+ target.flush
163
+ end
164
+ end
165
+
166
+ # :call-seq:
167
+ # write(content, options?)
168
+ # write(options?) { |bytes| .. }
169
+ #
170
+ # Writes to the resource behind the URI. The first form writes the content from a string or an object
171
+ # that responds to +read+ and optionally +size+. The second form writes the content by yielding to the
172
+ # block. Each yield should return up to the specified number of bytes, the last yield returns nil.
173
+ #
174
+ # For options, see URI::write.
175
+ def write(*args, &block)
176
+ options = args.pop if Hash === args.last
177
+ options ||= {}
178
+ if String === args.first
179
+ ios = StringIO.new(args.first, 'r')
180
+ write(options.merge(:size=>args.first.size)) { |bytes| ios.read(bytes) }
181
+ elsif args.first.respond_to?(:read)
182
+ size = args.first.size rescue nil
183
+ write({:size=>size}.merge(options)) { |bytes| args.first.read(bytes) }
184
+ elsif args.empty? && block
185
+ write_internal options, &block
186
+ else
187
+ raise ArgumentError, 'Either give me the content, or pass me a block, otherwise what would I upload?'
188
+ end
189
+ end
190
+
191
+ # :call-seq:
192
+ # upload(source, options?)
193
+ #
194
+ # Uploads from source to the resource.
195
+ #
196
+ # The source may be a file name (string or task), in which case the file is uploaded to the resource.
197
+ # If the source is a directory, uploads all files inside the directory (including nested directories).
198
+ # The source may also be any object that responds to +read+ (and optionally +size+), e.g. File, StringIO, Pipe.
199
+ #
200
+ # Use the progress bar when running in verbose mode.
201
+ def upload(source, options = nil)
202
+ source = source.name if Rake::Task === source
203
+ options ||= {}
204
+ if String === source
205
+ raise NotFoundError, 'No source file/directory to upload.' unless File.exist?(source)
206
+ if File.directory?(source)
207
+ Dir.glob("#{source}/**/*").reject { |file| File.directory?(file) }.each do |file|
208
+ uri = self + (File.join(self.path, file.sub(source, '')))
209
+ uri.upload file, {:digests=>[]}.merge(options)
210
+ end
211
+ else
212
+ File.open(source, 'rb') { |input| upload input, options }
213
+ end
214
+ elsif source.respond_to?(:read)
215
+ digests = (options[:digests] || [:md5, :sha1]).
216
+ inject({}) { |hash, name| hash[name] = Digest.const_get(name.to_s.upcase).new ; hash }
217
+ size = source.stat.size rescue nil
218
+ write (options).merge(:progress=>verbose && size, :size=>size) do |bytes|
219
+ source.read(bytes).tap do |chunk|
220
+ digests.values.each { |digest| digest << chunk } if chunk
221
+ end
222
+ end
223
+ digests.each do |key, digest|
224
+ self.merge("#{self.path}.#{key}").write digest.hexdigest,
225
+ (options).merge(:progress=>false)
226
+ end
227
+ else
228
+ raise ArgumentError, 'Expecting source to be a file name (string, task) or any object that responds to read (file, pipe).'
229
+ end
230
+ end
231
+
232
+ protected
233
+
234
+ # :call-seq:
235
+ # with_progress_bar(show, file_name, size) { |progress| ... }
236
+ #
237
+ # Displays a progress bar while executing the block. The first argument must be true for the
238
+ # progress bar to show (TTY output also required), as a convenient for selectively using the
239
+ # progress bar from a single block.
240
+ #
241
+ # The second argument provides a filename to display, the third its size in bytes.
242
+ #
243
+ # The block is yielded with a progress object that implements a single method.
244
+ # Call << for each block of bytes down/uploaded.
245
+ def with_progress_bar(show, file_name, size, &block) #:nodoc:
246
+ options = { :total=>size || 0, :title=>file_name }
247
+ options[:hidden] = true unless show
248
+ ProgressBar.start options, &block
249
+ end
250
+
251
+ # :call-seq:
252
+ # proxy_uri => URI?
253
+ #
254
+ # Returns the proxy server to use. Obtains the proxy from the relevant environment variable (e.g. HTTP_PROXY).
255
+ # Supports exclusions based on host name and port number from environment variable NO_PROXY.
256
+ def proxy_uri
257
+ proxy = ENV["#{scheme.upcase}_PROXY"]
258
+ proxy = URI.parse(proxy) if String === proxy
259
+ excludes = ENV['NO_PROXY'].to_s.split(/\s*,\s*/).compact
260
+ excludes = excludes.map { |exclude| exclude =~ /:\d+$/ ? exclude : "#{exclude}:*" }
261
+ return proxy unless excludes.any? { |exclude| File.fnmatch(exclude, "#{host}:#{port}") }
262
+ end
263
+
264
+ def write_internal(options, &block) #:nodoc:
265
+ fail 'This protocol doesn\'t support writing (yet, how about helping by implementing it?)'
266
+ end
267
+
268
+ end
269
+
270
+
271
+ class HTTP #:nodoc:
272
+
273
+ # See URI::Generic#read
274
+ def read(options = nil, &block)
275
+ options ||= {}
276
+
277
+ user = self.user || options[:username]
278
+ password = self.password || options[:password]
279
+
280
+ connect do |http|
281
+ trace "Requesting #{self}"
282
+ headers = { 'If-Modified-Since' => CGI.rfc1123_date(options[:modified].utc) } if options[:modified]
283
+ request = Net::HTTP::Get.new(request_uri.empty? ? '/' : request_uri, headers)
284
+ request.basic_auth user, password if user
285
+
286
+ http.request request do |response|
287
+ case response
288
+ when Net::HTTPNotModified
289
+ # No modification, nothing to do.
290
+ trace 'Not modified since last download'
291
+ return nil
292
+ when Net::HTTPRedirection
293
+ # Try to download from the new URI, handle relative redirects.
294
+ trace "Redirected to #{response['Location']}"
295
+ rself = self + URI.parse(response['Location'])
296
+ rself.user, rself.password = user, password
297
+ return rself.read(options, &block)
298
+ when Net::HTTPOK
299
+ info "Downloading #{self}"
300
+ result = nil
301
+ with_progress_bar options[:progress], path.split('/').last, response.content_length do |progress|
302
+ if block
303
+ response.read_body do |chunk|
304
+ block.call chunk
305
+ progress << chunk
306
+ end
307
+ else
308
+ result = ''
309
+ response.read_body do |chunk|
310
+ result << chunk
311
+ progress << chunk
312
+ end
313
+ end
314
+ end
315
+ return result
316
+ when Net::HTTPNotFound
317
+ raise NotFoundError, "Looking for #{self} and all I got was a 404!"
318
+ else
319
+ raise RuntimeError, "Failed to download #{self}: #{response.message}"
320
+ end
321
+ end
322
+ end
323
+ end
324
+
325
+ private
326
+
327
+ def write_internal(options, &block) #:nodoc:
328
+ options ||= {}
329
+ user = self.user || options[:username]
330
+ password = self.password || options[:password]
331
+
332
+ connect do |http|
333
+ trace "Uploading to #{path}"
334
+ content = StringIO.new
335
+ while chunk = yield(RW_CHUNK_SIZE)
336
+ content << chunk
337
+ end
338
+ headers = { 'Content-MD5'=>Digest::MD5.hexdigest(content.string), 'Content-Type'=>'application/octet-stream' }
339
+ request = Net::HTTP::Put.new(request_uri.empty? ? '/' : request_uri, headers)
340
+
341
+ request.basic_auth user, password if user
342
+
343
+ response = nil
344
+ with_progress_bar options[:progress], path.split('/').last, content.size do |progress|
345
+ request.content_length = content.size
346
+ content.rewind
347
+ stream = Object.new
348
+ class << stream ; self ;end.send :define_method, :read do |count|
349
+ bytes = content.read(count)
350
+ progress << bytes if bytes
351
+ bytes
352
+ end
353
+ request.body_stream = stream
354
+ response = http.request(request)
355
+ end
356
+
357
+ case response
358
+ when Net::HTTPRedirection
359
+ # Try to download from the new URI, handle relative redirects.
360
+ trace "Redirected to #{response['Location']}"
361
+ content.rewind
362
+ return (self + URI.parse(response['location'])).write_internal(options) { |bytes| content.read(bytes) }
363
+ when Net::HTTPSuccess
364
+ else
365
+ raise RuntimeError, "Failed to upload #{self}: #{response.message}"
366
+ end
367
+ end
368
+ end
369
+
370
+ def connect
371
+ if proxy = proxy_uri
372
+ proxy = URI.parse(proxy) if String === proxy
373
+ http = Net::HTTP.new(host, port, proxy.host, proxy.port, proxy.user, proxy.password)
374
+ else
375
+ http = Net::HTTP.new(host, port)
376
+ end
377
+ if self.instance_of? URI::HTTPS
378
+ require 'net/https'
379
+ http.use_ssl = true
380
+ end
381
+ yield http
382
+ end
383
+
384
+ end
385
+
386
+
387
+ class SFTP < Generic #:nodoc:
388
+
389
+ DEFAULT_PORT = 22
390
+ COMPONENT = [ :scheme, :userinfo, :host, :port, :path ].freeze
391
+
392
+ class << self
393
+ # Caching of passwords, so we only need to ask once.
394
+ def passwords
395
+ @passwords ||= {}
396
+ end
397
+ end
398
+
399
+ def initialize(*arg)
400
+ super
401
+ end
402
+
403
+ def read(options = {}, &block)
404
+ # SSH options are based on the username/password from the URI.
405
+ ssh_options = { :port=>port, :password=>password }.merge(options[:ssh_options] || {})
406
+ ssh_options[:password] ||= SFTP.passwords[host]
407
+ begin
408
+ trace "Connecting to #{host}"
409
+ if block
410
+ result = nil
411
+ else
412
+ result = ''
413
+ block = lambda { |chunk| result << chunk }
414
+ end
415
+ Net::SFTP.start(host, user, ssh_options) do |sftp|
416
+ SFTP.passwords[host] = ssh_options[:password]
417
+ trace 'connected'
418
+
419
+ with_progress_bar options[:progress] && options[:size], path.split('/').last, options[:size] || 0 do |progress|
420
+ trace "Downloading from #{path}"
421
+ sftp.file.open(path, 'r') do |file|
422
+ while chunk = file.read(RW_CHUNK_SIZE)
423
+ block.call chunk
424
+ progress << chunk
425
+ break if chunk.size < RW_CHUNK_SIZE
426
+ end
427
+ end
428
+ end
429
+ end
430
+ return result
431
+ rescue Net::SSH::AuthenticationFailed=>ex
432
+ # Only if running with console, prompt for password.
433
+ if !ssh_options[:password] && $stdout.isatty
434
+ password = ask("Password for #{host}:") { |q| q.echo = '*' }
435
+ ssh_options[:password] = password
436
+ retry
437
+ end
438
+ raise
439
+ end
440
+ end
441
+
442
+ protected
443
+
444
+ def write_internal(options, &block) #:nodoc:
445
+ # SSH options are based on the username/password from the URI.
446
+ ssh_options = { :port=>port, :password=>password }.merge(options[:ssh_options] || {})
447
+ ssh_options[:password] ||= SFTP.passwords[host]
448
+ begin
449
+ trace "Connecting to #{host}"
450
+ Net::SFTP.start(host, user, ssh_options) do |sftp|
451
+ SFTP.passwords[host] = ssh_options[:password]
452
+ trace 'Connected'
453
+
454
+ # To create a path, we need to create all its parent. We use realpath to determine if
455
+ # the path already exists, otherwise mkdir fails.
456
+ trace "Creating path #{path}"
457
+ File.dirname(path).split('/').reject(&:empty?).inject('/') do |base, part|
458
+ combined = base + part
459
+ sftp.close(sftp.opendir!(combined)) rescue sftp.mkdir! combined, {}
460
+ "#{combined}/"
461
+ end
462
+
463
+ with_progress_bar options[:progress] && options[:size], path.split('/').last, options[:size] || 0 do |progress|
464
+ trace "Uploading to #{path}"
465
+ sftp.file.open(path, 'w') do |file|
466
+ while chunk = yield(RW_CHUNK_SIZE)
467
+ file.write chunk
468
+ progress << chunk
469
+ end
470
+ sftp.setstat(path, :permissions => options[:permissions]) if options[:permissions]
471
+ end
472
+ end
473
+ end
474
+ rescue Net::SSH::AuthenticationFailed=>ex
475
+ # Only if running with console, prompt for password.
476
+ if !ssh_options[:password] && $stdout.isatty
477
+ password = ask("Password for #{host}:") { |q| q.echo = '*' }
478
+ ssh_options[:password] = password
479
+ retry
480
+ end
481
+ raise
482
+ end
483
+ end
484
+
485
+ end
486
+
487
+ @@schemes['SFTP'] = SFTP
488
+
489
+
490
+ # File URL. Keep in mind that file URLs take the form of <code>file://host/path</code>, although the host
491
+ # is not used, so typically all you will see are three backslashes. This methods accept common variants,
492
+ # like <code>file:/path</code> but always returns a valid URL.
493
+ class FILE < Generic
494
+
495
+ COMPONENT = [ :host, :path ].freeze
496
+
497
+ def upload(source, options = nil)
498
+ super
499
+ if File === source then
500
+ File.chmod(source.stat.mode, real_path)
501
+ end
502
+ end
503
+
504
+ def initialize(*args)
505
+ super
506
+ # file:something (opaque) becomes file:///something
507
+ if path.nil?
508
+ set_path "/#{opaque}"
509
+ unless opaque.nil?
510
+ set_opaque nil
511
+ warn "#{caller[2]}: We'll accept this URL, but just so you know, it needs three slashes, as in: #{to_s}"
512
+ end
513
+ end
514
+ # Sadly, file://something really means file://something/ (something being server)
515
+ set_path '/' if path.empty?
516
+
517
+ # On windows, file://c:/something is not a valid URL, but people do it anyway, so if we see a drive-as-host,
518
+ # we'll just be nice enough to fix it. (URI actually strips the colon here)
519
+ if host =~ /^[a-zA-Z]$/
520
+ set_path "/#{host}:#{path}"
521
+ set_host nil
522
+ end
523
+ end
524
+
525
+ # See URI::Generic#read
526
+ def read(options = nil, &block)
527
+ options ||= {}
528
+ 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
529
+
530
+ path = real_path
531
+ # TODO: complain about clunky URLs
532
+ raise NotFoundError, "Looking for #{self} and can't find it." unless File.exists?(path)
533
+ raise NotFoundError, "Looking for the file #{self}, and it happens to be a directory." if File.directory?(path)
534
+ File.open path, 'rb' do |input|
535
+ with_progress_bar options[:progress], path.split('/').last, input.stat.size do |progress|
536
+ block ? block.call(input.read) : input.read
537
+ end
538
+ end
539
+ end
540
+
541
+ def to_s
542
+ "file://#{host}#{path}"
543
+ end
544
+
545
+ # Returns the file system path based that corresponds to the URL path.
546
+ # On windows this method strips the leading slash off of the path.
547
+ # On all platforms this method unescapes the URL path.
548
+ def real_path #:nodoc:
549
+ real_path = Buildr::Util.win_os? && path =~ /^\/[a-zA-Z]:\// ? path[1..-1] : path
550
+ URI.unescape(real_path)
551
+ end
552
+
553
+ protected
554
+
555
+ def write_internal(options, &block) #:nodoc:
556
+ 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
557
+ temp = Tempfile.new(File.basename(path))
558
+ temp.binmode
559
+ with_progress_bar options[:progress] && options[:size], path.split('/').last, options[:size] || 0 do |progress|
560
+ while chunk = yield(RW_CHUNK_SIZE)
561
+ temp.write chunk
562
+ progress << chunk
563
+ end
564
+ end
565
+ temp.close
566
+ mkpath File.dirname(real_path)
567
+ mv temp.path, real_path
568
+ real_path
569
+ end
570
+
571
+ @@schemes['FILE'] = FILE
572
+
573
+ end
574
+
575
+ end