C0 code coverage information
Generated on Wed Oct 07 08:34:05 -0700 2009 with rcov 0.8.2.1
Code reported as executed by Ruby looks like this...
and this: this line is also marked as covered.
Lines considered as run by rcov, but not reported by Ruby, look like this,
and this: these lines were inferred by rcov (using simple heuristics).
Finally, here's a line marked as not executed.
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 'buildr/packaging/archive'
18
19
20 module Buildr
21
22 # The ZipTask creates a new Zip file. You can include any number of files and and directories,
23 # use exclusion patterns, and include files into specific directories.
24 #
25 # For example:
26 # zip('test.zip').tap do |task|
27 # task.include 'srcs'
28 # task.include 'README', 'LICENSE'
29 # end
30 #
31 # See Buildr#zip and ArchiveTask.
32 class ZipTask < ArchiveTask
33
34 # Compression leve for this Zip.
35 attr_accessor :compression_level
36
37 def initialize(*args) #:nodoc:
38 self.compression_level = Zlib::DEFAULT_COMPRESSION
39 super
40 end
41
42 # :call-seq:
43 # entry(name) => Entry
44 #
45 # Returns a ZIP file entry. You can use this to check if the entry exists and its contents,
46 # for example:
47 # package(:jar).entry("META-INF/LICENSE").should contain(/Apache Software License/)
48 def entry(entry_name)
49 ::Zip::ZipEntry.new(name, entry_name)
50 end
51
52 def entries #:nodoc:
53 @entries ||= Zip::ZipFile.open(name) { |zip| zip.entries }
54 end
55
56 private
57
58 def create_from(file_map)
59 Zip::ZipOutputStream.open name do |zip|
60 seen = {}
61 mkpath = lambda do |dir|
62 unless dir == '.' || seen[dir]
63 mkpath.call File.dirname(dir)
64 zip.put_next_entry(dir + '/', compression_level)
65 seen[dir] = true
66 end
67 end
68
69 file_map.each do |path, content|
70 mkpath.call File.dirname(path)
71 if content.respond_to?(:call)
72 zip.put_next_entry(path, compression_level)
73 content.call zip
74 elsif content.nil? || File.directory?(content.to_s)
75 mkpath.call path
76 else
77 entry = zip.put_next_entry(path, compression_level)
78 File.open content.to_s, 'rb' do |is|
79 entry.unix_perms = is.stat.mode & 07777
80 while data = is.read(4096)
81 zip << data
82 end
83 end
84 end
85 end
86 end
87 end
88
89 end
90
91
92 # :call-seq:
93 # zip(file) => ZipTask
94 #
95 # The ZipTask creates a new Zip file. You can include any number of files and
96 # and directories, use exclusion patterns, and include files into specific
97 # directories.
98 #
99 # For example:
100 # zip('test.zip').tap do |task|
101 # task.include 'srcs'
102 # task.include 'README', 'LICENSE'
103 # end
104 def zip(file)
105 ZipTask.define_task(file)
106 end
107
108
109 # An object for unzipping a file into a target directory. You can tell it to include
110 # or exclude only specific files and directories, and also to map files from particular
111 # paths inside the zip file into the target directory. Once ready, call #extract.
112 #
113 # Usually it is more convenient to create a file task for extracting the zip file
114 # (see #unzip) and pass this object as a prerequisite to other tasks.
115 #
116 # See Buildr#unzip.
117 class Unzip
118
119 # The zip file to extract.
120 attr_accessor :zip_file
121 # The target directory to extract to.
122 attr_accessor :target
123
124 # Initialize with hash argument of the form target=>zip_file.
125 def initialize(args)
126 @target, arg_names, zip_file = Buildr.application.resolve_args([args])
127 @zip_file = zip_file.first
128 @paths = {}
129 end
130
131 # :call-seq:
132 # extract
133 #
134 # Extract the zip file into the target directory.
135 #
136 # You can call this method directly. However, if you are using the #unzip method,
137 # it creates a file task for the target directory: use that task instead as a
138 # prerequisite. For example:
139 # build unzip(dir=>zip_file)
140 # Or:
141 # unzip(dir=>zip_file).target.invoke
142 def extract
143 # If no paths specified, then no include/exclude patterns
144 # specified. Nothing will happen unless we include all files.
145 if @paths.empty?
146 @paths[nil] = FromPath.new(self, nil)
147 end
148
149 # Otherwise, empty unzip creates target as a file when touching.
150 mkpath target.to_s
151 Zip::ZipFile.open(zip_file.to_s) do |zip|
152 entries = zip.collect
153 @paths.each do |path, patterns|
154 patterns.map(entries).each do |dest, entry|
155 next if entry.directory?
156 dest = File.expand_path(dest, target.to_s)
157 trace "Extracting #{dest}"
158 mkpath File.dirname(dest) rescue nil
159 entry.restore_permissions = true
160 entry.extract(dest) { true }
161 end
162 end
163 end
164 # Let other tasks know we updated the target directory.
165 touch target.to_s
166 end
167
168 # :call-seq:
169 # include(*files) => self
170 # include(*files, :path=>name) => self
171 #
172 # Include all files that match the patterns and returns self.
173 #
174 # Use include if you only want to unzip some of the files, by specifying
175 # them instead of using exclusion. You can use #include in combination
176 # with #exclude.
177 def include(*files)
178 if Hash === files.last
179 from_path(files.pop[:path]).include *files
180 else
181 from_path(nil).include *files
182 end
183 self
184 end
185 alias :add :include
186
187 # :call-seq:
188 # exclude(*files) => self
189 #
190 # Exclude all files that match the patterns and return self.
191 #
192 # Use exclude to unzip all files except those that match the pattern.
193 # You can use #exclude in combination with #include.
194 def exclude(*files)
195 if Hash === files.last
196 from_path(files.pop[:path]).exclude *files
197 else
198 from_path(nil).exclude *files
199 end
200 self
201 end
202
203 # :call-seq:
204 # from_path(name) => Path
205 #
206 # Allows you to unzip from a path. Returns an object you can use to
207 # specify which files to include/exclude relative to that path.
208 # Expands the file relative to that path.
209 #
210 # For example:
211 # unzip(Dir.pwd=>'test.jar').from_path('etc').include('LICENSE')
212 # will unzip etc/LICENSE into ./LICENSE.
213 #
214 # This is different from:
215 # unzip(Dir.pwd=>'test.jar').include('etc/LICENSE')
216 # which unzips etc/LICENSE into ./etc/LICENSE.
217 def from_path(name)
218 @paths[name] ||= FromPath.new(self, name)
219 end
220 alias :path :from_path
221
222 # :call-seq:
223 # root => Unzip
224 #
225 # Returns the root path, essentially the Unzip object itself. In case you are wondering
226 # down paths and want to go back.
227 def root
228 self
229 end
230
231 # Returns the path to the target directory.
232 def to_s
233 target.to_s
234 end
235
236 class FromPath #:nodoc:
237
238 def initialize(unzip, path)
239 @unzip = unzip
240 if path
241 @path = path[-1] == ?/ ? path : path + '/'
242 else
243 @path = ''
244 end
245 end
246
247 # See UnzipTask#include
248 def include(*files) #:doc:
249 @include ||= []
250 @include |= files
251 self
252 end
253
254 # See UnzipTask#exclude
255 def exclude(*files) #:doc:
256 @exclude ||= []
257 @exclude |= files
258 self
259 end
260
261 def map(entries)
262 includes = @include || ['*']
263 excludes = @exclude || []
264 entries.inject({}) do |map, entry|
265 if entry.name =~ /^#{@path}/
266 short = entry.name.sub(@path, '')
267 if includes.any? { |pat| File.fnmatch(pat, short) } &&
268 !excludes.any? { |pat| File.fnmatch(pat, short) }
269 map[short] = entry
270 end
271 end
272 map
273 end
274 end
275
276 # Documented in Unzip.
277 def root
278 @unzip
279 end
280
281 # The target directory to extract to.
282 def target
283 @unzip.target
284 end
285
286 end
287
288 end
289
290 # :call-seq:
291 # unzip(to_dir=>zip_file) => Zip
292 #
293 # Creates a task that will unzip a file into the target directory. The task name
294 # is the target directory, the prerequisite is the file to unzip.
295 #
296 # This method creates a file task to expand the zip file. It returns an Unzip object
297 # that specifies how the file will be extracted. You can include or exclude specific
298 # files from within the zip, and map to different paths.
299 #
300 # The Unzip object's to_s method return the path to the target directory, so you can
301 # use it as a prerequisite. By keeping the Unzip object separate from the file task,
302 # you overlay additional work on top of the file task.
303 #
304 # For example:
305 # unzip('all'=>'test.zip')
306 # unzip('src'=>'test.zip').include('README', 'LICENSE')
307 # unzip('libs'=>'test.zip').from_path('libs')
308 def unzip(args)
309 target, arg_names, zip_file = Buildr.application.resolve_args([args])
310 task = file(File.expand_path(target.to_s)=>zip_file)
311 Unzip.new(task=>zip_file).tap do |setup|
312 task.enhance { setup.extract }
313 end
314 end
315
316 end
Generated using the rcov code coverage analysis tool for Ruby
version 0.8.2.1.