Buildr C0 Coverage Information - RCov

lib/buildr/packaging/ziptask.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
lib/buildr/packaging/ziptask.rb 356 185
12.64%
15.68%

Key

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.

Coverage Details

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           dirname = (dir[-1..-1] =~ /\/$/) ? dir : dir + '/'
63           unless dir == '.' || seen[dirname]
64             mkpath.call File.dirname(dirname)
65             zip.put_next_entry(dirname, compression_level)
66             seen[dirname] = true
67           end
68         end
69 
70         file_map.each do |path, content|
71           warn "Warning:  Path in zipfile #{name} contains backslash: #{path}" if path =~ /\\/
72           mkpath.call File.dirname(path)
73           if content.respond_to?(:call)
74             zip.put_next_entry(path, compression_level)
75             content.call zip
76           elsif content.nil? || File.directory?(content.to_s)
77             mkpath.call path
78           else
79             entry = zip.put_next_entry(path, compression_level)
80             File.open content.to_s, 'rb' do |is|
81               entry.unix_perms = is.stat.mode & 07777
82               while data = is.read(4096)
83                 zip << data
84               end
85             end
86           end
87         end
88       end
89     end
90 
91   end
92 
93 
94   # :call-seq:
95   #    zip(file) => ZipTask
96   #
97   # The ZipTask creates a new Zip file. You can include any number of files and
98   # and directories, use exclusion patterns, and include files into specific
99   # directories.
100   #
101   # For example:
102   #   zip('test.zip').tap do |task|
103   #     task.include 'srcs'
104   #     task.include 'README', 'LICENSE'
105   #   end
106   def zip(file)
107     ZipTask.define_task(file)
108   end
109 
110 
111   # An object for unzipping/untarring a file into a target directory. You can tell it to include
112   # or exclude only specific files and directories, and also to map files from particular
113   # paths inside the zip file into the target directory. Once ready, call #extract.
114   #
115   # Usually it is more convenient to create a file task for extracting the zip file
116   # (see #unzip) and pass this object as a prerequisite to other tasks.
117   #
118   # See Buildr#unzip.
119   class Unzip
120 
121     # The zip file to extract.
122     attr_accessor :zip_file
123     # The target directory to extract to.
124     attr_accessor :target
125 
126     # Initialize with hash argument of the form target=>zip_file.
127     def initialize(args)
128       @target, arg_names, zip_file = Buildr.application.resolve_args([args])
129       @zip_file = zip_file.first
130       @paths = {}
131     end
132 
133     # :call-seq:
134     #   extract
135     #
136     # Extract the zip/tgz file into the target directory.
137     #
138     # You can call this method directly. However, if you are using the #unzip method,
139     # it creates a file task for the target directory: use that task instead as a
140     # prerequisite. For example:
141     #   build unzip(dir=>zip_file)
142     # Or:
143     #   unzip(dir=>zip_file).target.invoke
144     def extract
145       # If no paths specified, then no include/exclude patterns
146       # specified. Nothing will happen unless we include all files.
147       if @paths.empty?
148         @paths[nil] = FromPath.new(self, nil)
149       end
150 
151       # Otherwise, empty unzip creates target as a file when touching.
152       mkpath target.to_s
153       if zip_file.to_s.match /\.t?gz$/
154         #un-tar.gz
155         Zlib::GzipReader.open(zip_file.to_s) { |tar|
156           Archive::Tar::Minitar::Input.open(tar) do |inp|
157             inp.each do |tar_entry|
158               @paths.each do |path, patterns|
159                 patterns.map([tar_entry]).each do |dest, entry|
160                   next if entry.directory?
161                   dest = File.expand_path(dest, target.to_s)
162                   trace "Extracting #{dest}"
163                   mkpath File.dirname(dest) rescue nil
164                   #entry.restore_permissions = true
165                   File.open(dest, 'wb') {|f| f.write entry.read}
166                 end
167               end
168             end
169           end
170         }
171       else
172         Zip::ZipFile.open(zip_file.to_s) do |zip|
173           entries = zip.collect
174           @paths.each do |path, patterns|
175             patterns.map(entries).each do |dest, entry|
176               next if entry.directory?
177               dest = File.expand_path(dest, target.to_s)
178               trace "Extracting #{dest}"
179               mkpath File.dirname(dest) rescue nil
180               entry.restore_permissions = true
181               entry.extract(dest) { true }
182             end
183           end
184         end
185       end
186       # Let other tasks know we updated the target directory.
187       touch target.to_s
188     end
189 
190     #reads the includes/excludes and apply them to the entry_name
191     def included?(entry_name)
192       @paths.each do |path, patterns|
193         return true if path.nil?
194         if entry_name =~ /^#{path}/
195           short = entry_name.sub(path, '')
196           if patterns.include.any? { |pattern| File.fnmatch(pattern, entry_name) } &&
197             !patterns.exclude.any? { |pattern| File.fnmatch(pattern, entry_name) }
198             # trace "tar_entry.full_name " + entry_name + " is included"
199             return true
200           end
201         end
202       end
203       # trace "tar_entry.full_name " + entry_name + " is excluded"
204       return false
205     end
206 
207 
208     # :call-seq:
209     #   include(*files) => self
210     #   include(*files, :path=>name) => self
211     #
212     # Include all files that match the patterns and returns self.
213     #
214     # Use include if you only want to unzip some of the files, by specifying
215     # them instead of using exclusion. You can use #include in combination
216     # with #exclude.
217     def include(*files)
218       if Hash === files.last
219         from_path(files.pop[:path]).include *files
220       else
221         from_path(nil).include *files
222       end
223       self
224     end
225     alias :add :include
226 
227     # :call-seq:
228     #   exclude(*files) => self
229     #
230     # Exclude all files that match the patterns and return self.
231     #
232     # Use exclude to unzip all files except those that match the pattern.
233     # You can use #exclude in combination with #include.
234     def exclude(*files)
235       if Hash === files.last
236         from_path(files.pop[:path]).exclude *files
237       else
238         from_path(nil).exclude *files
239       end
240       self
241     end
242 
243     # :call-seq:
244     #   from_path(name) => Path
245     #
246     # Allows you to unzip from a path. Returns an object you can use to
247     # specify which files to include/exclude relative to that path.
248     # Expands the file relative to that path.
249     #
250     # For example:
251     #   unzip(Dir.pwd=>'test.jar').from_path('etc').include('LICENSE')
252     # will unzip etc/LICENSE into ./LICENSE.
253     #
254     # This is different from:
255     #  unzip(Dir.pwd=>'test.jar').include('etc/LICENSE')
256     # which unzips etc/LICENSE into ./etc/LICENSE.
257     def from_path(name)
258       @paths[name] ||= FromPath.new(self, name)
259     end
260     alias :path :from_path
261 
262     # :call-seq:
263     #   root => Unzip
264     #
265     # Returns the root path, essentially the Unzip object itself. In case you are wondering
266     # down paths and want to go back.
267     def root
268       self
269     end
270 
271     # Returns the path to the target directory.
272     def to_s
273       target.to_s
274     end
275 
276     class FromPath #:nodoc:
277 
278       def initialize(unzip, path)
279         @unzip = unzip
280         if path
281           @path = path[-1] == ?/ ? path : path + '/'
282         else
283           @path = ''
284         end
285       end
286 
287       # See UnzipTask#include
288       def include(*files) #:doc:
289         @include ||= []
290         @include |= files
291         self
292       end
293 
294       # See UnzipTask#exclude
295       def exclude(*files) #:doc:
296         @exclude ||= []
297         @exclude |= files
298         self
299       end
300 
301       def map(entries)
302         includes = @include || ['*']
303         excludes = @exclude || []
304         entries.inject({}) do |map, entry|
305           if entry.name =~ /^#{@path}/
306             short = entry.name.sub(@path, '')
307             if includes.any? { |pat| File.fnmatch(pat, short) } &&
308                !excludes.any? { |pat| File.fnmatch(pat, short) }
309               map[short] = entry
310             end
311           end
312           map
313         end
314       end
315 
316       # Documented in Unzip.
317       def root
318         @unzip
319       end
320 
321       # The target directory to extract to.
322       def target
323         @unzip.target
324       end
325 
326     end
327 
328   end
329 
330   # :call-seq:
331   #    unzip(to_dir=>zip_file) => Zip
332   #
333   # Creates a task that will unzip a file into the target directory. The task name
334   # is the target directory, the prerequisite is the file to unzip.
335   #
336   # This method creates a file task to expand the zip file. It returns an Unzip object
337   # that specifies how the file will be extracted. You can include or exclude specific
338   # files from within the zip, and map to different paths.
339   #
340   # The Unzip object's to_s method return the path to the target directory, so you can
341   # use it as a prerequisite. By keeping the Unzip object separate from the file task,
342   # you overlay additional work on top of the file task.
343   #
344   # For example:
345   #   unzip('all'=>'test.zip')
346   #   unzip('src'=>'test.zip').include('README', 'LICENSE')
347   #   unzip('libs'=>'test.zip').from_path('libs')
348   def unzip(args)
349     target, arg_names, zip_file = Buildr.application.resolve_args([args])
350     task = file(File.expand_path(target.to_s)=>zip_file)
351     Unzip.new(task=>zip_file).tap do |setup|
352       task.enhance { setup.extract }
353     end
354   end
355 
356 end

Generated on 2011-07-06 23:35:38 -0700 with rcov 0.9.8