Update version according to OSCI-883
[packages/precise/mcollective.git] / plugins / mcollective / pluginpackager / debpackage_packager.rb
1 module MCollective
2   module PluginPackager
3     class DebpackagePackager
4       require 'erb'
5
6       def initialize(plugin, pluginpath = nil, signature = nil, verbose = false, keep_artifacts = nil, module_template = nil)
7         if PluginPackager.command_available?('debuild')
8           @plugin = plugin
9           @verbose = verbose
10           @libdir = pluginpath || '/usr/share/mcollective/plugins/mcollective/'
11           @signature = signature
12           @package_name = "#{@plugin.mcname}-#{@plugin.metadata[:name]}"
13           @keep_artifacts = keep_artifacts
14         else
15           raise("Cannot build package. 'debuild' is not present on the system.")
16         end
17       end
18
19       # Build process :
20       # - create buildroot
21       # - craete buildroot/debian
22       # - create the relative directories with package contents
23       # - create install files for each of the plugins that are going to be built
24       # - create debian build files
25       # - create tarball
26       # - create pre and post install files
27       # - run the build script
28       # - move packages to cwd
29       # - clean up
30       def create_packages
31         begin
32           puts "Building packages for #{@package_name} plugin."
33
34           @tmpdir = Dir.mktmpdir('mcollective_packager')
35           @build_dir = File.join(@tmpdir, "#{@package_name}_#{@plugin.metadata[:version]}")
36           Dir.mkdir(@build_dir)
37
38           create_debian_dir
39           @plugin.packagedata.each do |type, data|
40             prepare_tmpdirs(data)
41             create_install_file(type, data)
42             create_pre_and_post_install(type)
43           end
44           create_debian_files
45           create_tar
46           run_build
47           move_packages
48
49           puts "Completed building all packages for #{@package_name} plugin."
50         ensure
51           if @keep_artifacts
52             puts 'Keeping build artifacts.'
53             puts "Build artifacts saved - #{@tmpdir}"
54           else
55             puts 'Removing build artifacts.'
56             cleanup_tmpdirs
57           end
58         end
59       end
60
61       private
62
63       def create_debian_files
64         ['control', 'Makefile', 'compat', 'rules', 'copyright', 'changelog'].each do |f|
65           create_file(f)
66         end
67       end
68
69       def run_build
70         FileUtils.cd(@build_dir) do
71           PluginPackager.execute_verbosely(@verbose) do
72             if @signature
73               if @signature.is_a?(String)
74                 PluginPackager.safe_system("debuild --no-lintian -i -k#{@signature}")
75               else
76                 PluginPackager.safe_system("debuild --no-lintian -i")
77               end
78             else
79               PluginPackager.safe_system("debuild --no-lintian -i -us -uc")
80             end
81           end
82         end
83       end
84
85       # Creates a string used by the control file to specify dependencies
86       # Dependencies can be formatted as :
87       # foo (>= x.x-x)
88       # foo (>= x.x)
89       # foo
90       def build_dependency_string(data)
91         dependencies = []
92         PluginPackager.filter_dependencies('debian', data[:dependencies]).each do |dep|
93           if dep[:version] && dep[:revision]
94             dependencies << "#{dep[:name]} (>=#{dep[:version]}-#{dep[:revision]})"
95           elsif dep[:version]
96             dependencies << "#{dep[:name]} (>=#{dep[:version]})"
97           else
98             dependencies << dep[:name]
99           end
100         end
101
102         if data[:plugindependency]
103           dependencies << "#{data[:plugindependency][:name]} (= ${binary:Version})"
104         end
105
106         dependencies.join(', ')
107       end
108
109       # Creates an install file for each of the packages that are going to be created
110       # for the plugin
111       def create_install_file(type, data)
112         install_file = "#{@package_name}-#{type}"
113         begin
114           install_file = File.join(@build_dir, 'debian', "#{install_file}.install")
115           File.open(install_file, 'w') do |file|
116             data[:files].each do |f|
117               extended_filename = File.join(@libdir, File.expand_path(f).gsub(/^#{@plugin.target_path}/, ''))
118               file.puts "#{extended_filename} #{File.dirname(extended_filename)}"
119             end
120           end
121         rescue Errno::EACCES => e
122           puts "Could not create install file '#{install_file}'. Permission denied"
123           raise e
124         rescue => e
125           puts "Could not create install file '#{install_file}'."
126           raise e
127         end
128       end
129
130       # Move source package and debs to cwd
131       def move_packages
132         begin
133           files_to_copy = Dir.glob(File.join(@tmpdir, '*.{deb,dsc,diff.gz,orig.tar.gz,changes}'))
134           FileUtils.cp(files_to_copy, '.')
135         rescue => e
136           puts 'Could not copy packages to working directory.'
137           raise e
138         end
139       end
140
141       # Create pre and post install files in $buildroot/debian
142       # from supplied scripts.
143       # Note that all packages built for the plugin will invoke
144       # the same pre and post install scripts.
145       def create_pre_and_post_install(type)
146         if @plugin.preinstall
147           if !File.exists?(@plugin.preinstall)
148             puts "pre-install script '#{@plugin.preinstall}' not found."
149             raise(Errno::ENOENT, @plugin.preinstall)
150           else
151             FileUtils.cp(@plugin.preinstall, File.join(@build_dir, 'debian', "#{@package_name}-#{type}.preinst"))
152           end
153         end
154
155         if @plugin.postinstall
156           if !File.exists?(@plugin.postinstall)
157             puts "post-install script '#{@plugin.postinstall}' not found."
158             raise(Errno::ENOENT, @plugin.postinstall)
159           else
160             FileUtils.cp(@plugin.postinstall, File.join(@build_dir, 'debian', "#{@package_name}-#{type}.postinst"))
161           end
162         end
163       end
164
165       # Tar up source
166       # Expects directory : $mcollective-$agent_$version
167       # Creates file : $buildroot/$mcollective-$agent_$version.orig.tar.gz
168       def create_tar
169         name_and_version = "#{@package_name}_#{@plugin.metadata[:version]}"
170         tarfile = "#{name_and_version}.orig.tar.gz"
171         begin
172           PluginPackager.execute_verbosely(@verbose) do
173             Dir.chdir(@tmpdir) do
174               PluginPackager.safe_system("tar -Pcvzf #{File.join(@tmpdir, tarfile)} #{name_and_version}")
175             end
176           end
177         rescue Exception => e
178           puts "Could not create tarball - #{tarfile}"
179           raise e
180         end
181       end
182
183       def create_file(filename)
184         begin
185           file = ERB.new(File.read(File.join(File.dirname(__FILE__), 'templates', 'debian', "#{filename}.erb")), nil, '-')
186           File.open(File.join(@build_dir, 'debian', filename), 'w') do |f|
187             f.puts file.result(binding)
188           end
189         rescue => e
190           puts "Could not create file - '#{filename}'"
191           raise e
192         end
193       end
194
195       # Move files contained in the plugin to the correct directory
196       # relative to the build root.
197       def prepare_tmpdirs(data)
198         data[:files].each do |file|
199           begin
200             targetdir = File.join(@build_dir, @libdir, File.dirname(File.expand_path(file)).gsub(/^#{@plugin.target_path}/, ""))
201             FileUtils.mkdir_p(targetdir) unless File.directory?(targetdir)
202             FileUtils.cp_r(file, targetdir)
203           rescue Errno::EACCES => e
204             puts "Could not create directory '#{targetdir}'. Permission denied"
205             raise e
206           rescue Errno::ENOENT => e
207             puts "Could not copy file '#{file}' to '#{targetdir}'. File does not exist"
208             raise e
209           rescue => e
210             puts 'Could not prepare build directory'
211             raise e
212           end
213         end
214       end
215
216       # Create the $buildroot/debian directory
217       def create_debian_dir
218         deb_dir = File.join(@build_dir, 'debian')
219         begin
220           FileUtils.mkdir_p(deb_dir)
221         rescue => e
222           puts "Could not create directory '#{deb_dir}'"
223           raise e
224         end
225       end
226
227       def cleanup_tmpdirs
228         begin
229           FileUtils.rm_r(@tmpdir) if File.directory?(@tmpdir)
230         rescue => e
231           puts "Could not remove temporary build directory - '#{@tmpdir}'"
232           raise e
233         end
234       end
235     end
236   end
237 end