1# Define a package task library to aid in the definition of
2# redistributable package files.
3
4require 'rake'
5require 'rake/tasklib'
6
7module Rake
8
9  # Create a packaging task that will package the project into
10  # distributable files (e.g zip archive or tar files).
11  #
12  # The PackageTask will create the following targets:
13  #
14  # [<b>:package</b>]
15  #   Create all the requested package files.
16  #
17  # [<b>:clobber_package</b>]
18  #   Delete all the package files.  This target is automatically
19  #   added to the main clobber target.
20  #
21  # [<b>:repackage</b>]
22  #   Rebuild the package files from scratch, even if they are not out
23  #   of date.
24  #
25  # [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tgz"</b>]
26  #   Create a gzipped tar package (if <em>need_tar</em> is true).
27  #
28  # [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.gz"</b>]
29  #   Create a gzipped tar package (if <em>need_tar_gz</em> is true).
30  #
31  # [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.bz2"</b>]
32  #   Create a bzip2'd tar package (if <em>need_tar_bz2</em> is true).
33  #
34  # [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.zip"</b>]
35  #   Create a zip package archive (if <em>need_zip</em> is true).
36  #
37  # Example:
38  #
39  #   Rake::PackageTask.new("rake", "1.2.3") do |p|
40  #     p.need_tar = true
41  #     p.package_files.include("lib/**/*.rb")
42  #   end
43  #
44  class PackageTask < TaskLib
45    # Name of the package (from the GEM Spec).
46    attr_accessor :name
47
48    # Version of the package (e.g. '1.3.2').
49    attr_accessor :version
50
51    # Directory used to store the package files (default is 'pkg').
52    attr_accessor :package_dir
53
54    # True if a gzipped tar file (tgz) should be produced (default is false).
55    attr_accessor :need_tar
56
57    # True if a gzipped tar file (tar.gz) should be produced (default is false).
58    attr_accessor :need_tar_gz
59
60    # True if a bzip2'd tar file (tar.bz2) should be produced (default is false).
61    attr_accessor :need_tar_bz2
62
63    # True if a zip file should be produced (default is false)
64    attr_accessor :need_zip
65
66    # List of files to be included in the package.
67    attr_accessor :package_files
68
69    # Tar command for gzipped or bzip2ed archives.  The default is 'tar'.
70    attr_accessor :tar_command
71
72    # Zip command for zipped archives.  The default is 'zip'.
73    attr_accessor :zip_command
74
75    # Create a Package Task with the given name and version.  Use +:noversion+
76    # as the version to build a package without a version or to provide a
77    # fully-versioned package name.
78
79    def initialize(name=nil, version=nil)
80      init(name, version)
81      yield self if block_given?
82      define unless name.nil?
83    end
84
85    # Initialization that bypasses the "yield self" and "define" step.
86    def init(name, version)
87      @name = name
88      @version = version
89      @package_files = Rake::FileList.new
90      @package_dir = 'pkg'
91      @need_tar = false
92      @need_tar_gz = false
93      @need_tar_bz2 = false
94      @need_zip = false
95      @tar_command = 'tar'
96      @zip_command = 'zip'
97    end
98
99    # Create the tasks defined by this task library.
100    def define
101      fail "Version required (or :noversion)" if @version.nil?
102      @version = nil if :noversion == @version
103
104      desc "Build all the packages"
105      task :package
106
107      desc "Force a rebuild of the package files"
108      task :repackage => [:clobber_package, :package]
109
110      desc "Remove package products"
111      task :clobber_package do
112        rm_r package_dir rescue nil
113      end
114
115      task :clobber => [:clobber_package]
116
117      [
118        [need_tar, tgz_file, "z"],
119        [need_tar_gz, tar_gz_file, "z"],
120        [need_tar_bz2, tar_bz2_file, "j"]
121      ].each do |(need, file, flag)|
122        if need
123          task :package => ["#{package_dir}/#{file}"]
124          file "#{package_dir}/#{file}" => [package_dir_path] + package_files do
125            chdir(package_dir) do
126              sh %{#{@tar_command} #{flag}cvf #{file} #{package_name}}
127            end
128          end
129        end
130      end
131
132      if need_zip
133        task :package => ["#{package_dir}/#{zip_file}"]
134        file "#{package_dir}/#{zip_file}" => [package_dir_path] + package_files do
135          chdir(package_dir) do
136            sh %{#{@zip_command} -r #{zip_file} #{package_name}}
137          end
138        end
139      end
140
141      directory package_dir
142
143      file package_dir_path => @package_files do
144        mkdir_p package_dir rescue nil
145        @package_files.each do |fn|
146          f = File.join(package_dir_path, fn)
147          fdir = File.dirname(f)
148          mkdir_p(fdir) if !File.exist?(fdir)
149          if File.directory?(fn)
150            mkdir_p(f)
151          else
152            rm_f f
153            safe_ln(fn, f)
154          end
155        end
156      end
157      self
158    end
159
160    def package_name
161      @version ? "#{@name}-#{@version}" : @name
162    end
163
164    def package_dir_path
165      "#{package_dir}/#{package_name}"
166    end
167
168    def tgz_file
169      "#{package_name}.tgz"
170    end
171
172    def tar_gz_file
173      "#{package_name}.tar.gz"
174    end
175
176    def tar_bz2_file
177      "#{package_name}.tar.bz2"
178    end
179
180    def zip_file
181      "#{package_name}.zip"
182    end
183  end
184
185end
186