Class: Buildr::ArchiveTask

Inherits:
Rake::FileTask show all
Defined in:
lib/buildr/packaging/archive.rb

Overview

Base class for ZipTask, TarTask and other archives.

Direct Known Subclasses

PackageGemTask, TarTask, ZipTask

Defined Under Namespace

Classes: Merge, Path, ZipExpander

Instance Method Summary collapse

Methods inherited from Rake::FileTask

#exist?

Constructor Details

#initialize(*args) ⇒ ArchiveTask

:nodoc:



310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/buildr/packaging/archive.rb', line 310

def initialize(*args) #:nodoc:
  super
  clean

  # Make sure we're the last enhancements, so other enhancements can add content.
  enhance do
    @file_map = {}
    enhance do
      send 'create' if respond_to?(:create)
      # We're here because the archive file does not exist, or one of the files is newer than the archive contents;
      # we need to make sure the archive doesn't exist (e.g. opening an existing Zip will add instead of create).
      # We also want to protect against partial updates.
      rm name rescue nil
      mkpath File.dirname(name)
      begin
        @paths.each do |name, object|
          @file_map[name] = nil unless name.empty?
          object.add_files(@file_map)
        end
        create_from @file_map
      rescue
        rm name rescue nil
        raise
      end
    end
  end
end

Instance Method Details

#cleanObject

:call-seq:

clean => self

Removes all previously added content from this archive. Use this method if you want to remove default content from a package. For example, package(:jar) by default includes compiled classes and resources, using this method, you can create an empty jar and afterwards add the desired content to it.

package(:jar).clean.include path_to('desired/content')


348
349
350
351
352
# File 'lib/buildr/packaging/archive.rb', line 348

def clean
  @paths = { '' => Path.new(self, '') }
  @prepares = []
  self
end

#contain?(*files) ⇒ Boolean

:call-seq:

contain(file*) => boolean

Returns true if this ZIP file contains all the specified files. You can use absolute file names and glob patterns (using *, **, etc).

Returns:

  • (Boolean)


514
515
516
# File 'lib/buildr/packaging/archive.rb', line 514

def contain?(*files)
  path("").contain?(*files)
end

#empty?Boolean

:call-seq:

empty? => boolean

Returns true if this ZIP file is empty (has no other entries inside).

Returns:

  • (Boolean)


505
506
507
# File 'lib/buildr/packaging/archive.rb', line 505

def empty?
  path("").empty
end

#exclude(*files) ⇒ Object

:call-seq:

exclude(*files) => self

Excludes files and returns self. Can be used in combination with include to prevent some files from being included.



398
399
400
401
# File 'lib/buildr/packaging/archive.rb', line 398

def exclude(*files)
  @paths[''].exclude *files
  self
end

#include(*files) ⇒ Object Also known as: add, <<

:call-seq:

include(*files) => self
include(*files, :path=>path) => self
include(file, :as=>name) => self
include(:from=>path) => self
include(*files, :merge=>true) => self

Include files in this archive, or when called on a path, within that path. Returns self.

The first form accepts a list of files, directories and glob patterns and adds them to the archive. For example, to include the file foo, directory bar (including all files in there) and all files under baz:

zip(..).include('foo', 'bar', 'baz/*')

The second form is similar but adds files/directories under the specified path. For example, to add foo as bar/foo:

zip(..).include('foo', :path=>'bar')

The :path option is the same as using the path method:

zip(..).path('bar').include('foo')

All other options can be used in combination with the :path option.

The third form adds a file or directory under a different name. For example, to add the file foo under the name bar:

zip(..).include('foo', :as=>'bar')

The fourth form adds the contents of a directory using the directory as a prerequisite:

zip(..).include(:from=>'foo')

Unlike include('foo') it includes the contents of the directory, not the directory itself. Unlike include('foo/*'), it uses the directory timestamp for dependency management.

The fifth form includes the contents of another archive by expanding it into this archive. For example:

zip(..).include('foo.zip', :merge=>true).include('bar.zip')

You can also use the method #merge.



386
387
388
389
390
# File 'lib/buildr/packaging/archive.rb', line 386

def include(*files)
  fail "AchiveTask.include() called with nil values" if files.include? nil
  @paths[''].include *files if files.compact.size > 0
  self
end

#invoke_prerequisites(args, chain) ⇒ Object

:nodoc:



469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/buildr/packaging/archive.rb', line 469

def invoke_prerequisites(args, chain) #:nodoc:
  @prepares.each { |prepare| prepare.call(self) }
  @prepares.clear

  file_map = {}
  @paths.each do |name, path|
    path.add_files(file_map)
  end

  # filter out Procs (dynamic content), nils and others
  @prerequisites |= file_map.values.select { |src| src.is_a?(String) || src.is_a?(Rake::Task) }

  super
end

#merge(*files) ⇒ Object

:call-seq:

merge(*files) => Merge
merge(*files, :path=>name) => Merge

Merges another archive into this one by including the individual files from the merged archive.

Returns an object that supports two methods: include and exclude. You can use these methods to merge only specific files. For example:

zip(..).merge('src.zip').include('module1/*')


412
413
414
# File 'lib/buildr/packaging/archive.rb', line 412

def merge(*files)
  @paths[''].merge *files
end

#needed?Boolean

:nodoc:

Returns:

  • (Boolean)


484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
# File 'lib/buildr/packaging/archive.rb', line 484

def needed? #:nodoc:
  return true unless File.exist?(name)
  # You can do something like:
  #   include('foo', :path=>'foo').exclude('foo/bar', path=>'foo').
  #     include('foo/bar', :path=>'foo/bar')
  # This will play havoc if we handled all the prerequisites together
  # under the task, so instead we handle them individually for each path.
  #
  # We need to check that any file we include is not newer than the
  # contents of the Zip. The file itself but also the directory it's
  # coming from, since some tasks touch the directory, e.g. when the
  # content of target/classes is included into a WAR.
  most_recent = @paths.collect { |name, path| path.sources }.flatten.
    select { |file| File.exist?(file) }.collect { |file| File.stat(file).mtime }.max
  File.stat(name).mtime < (most_recent || Rake::EARLY) || super
end

#path(name) ⇒ Object

:call-seq:

path(name) => Path

Returns a path object. Use the path object to include files under a path, for example, to include the file ‘foo’ as ‘bar/foo’:

zip(..).path('bar').include('foo')

Returns a Path object. The Path object implements all the same methods, like include, exclude, merge and so forth. It also implements path and root, so that:

path('foo').path('bar') == path('foo/bar')
path('foo').root == root


427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/buildr/packaging/archive.rb', line 427

def path(name)
  return @paths[''] if name.nil?
  normalized = name.split('/').inject([]) do |path, part|
    case part
    when '.', nil, ''
      path
    when '..'
      path[0...-1]
    else
      path << part
    end
  end.join('/')
  @paths[normalized] ||= Path.new(self, normalized)
end

#rootObject

:call-seq:

root => ArchiveTask

Call this on an archive to return itself, and on a path to return the archive.



446
447
448
# File 'lib/buildr/packaging/archive.rb', line 446

def root
  self
end

#with(options) ⇒ Object

:call-seq:

with(options) => self

Passes options to the task and returns self. Some tasks support additional options, for example, the WarTask supports options like :manifest, :libs and :classes.

For example:

package(:jar).with(:manifest=>'MANIFEST_MF')


458
459
460
461
462
463
464
465
466
467
# File 'lib/buildr/packaging/archive.rb', line 458

def with(options)
  options.each do |key, value|
    begin
      send "#{key}=", value
    rescue NoMethodError
      raise ArgumentError, "#{self.class.name} does not support the option #{key}"
    end
  end
  self
end