Class: Pkgr::Builder
- Inherits:
-
Object
- Object
- Pkgr::Builder
- Defined in:
- lib/pkgr/builder.rb
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#tarball ⇒ Object
readonly
Returns the value of attribute tarball.
Instance Method Summary collapse
-
#app_home_dir ⇒ Object
Some buildpacks may need the target home dir to exist.
-
#build_dir ⇒ Object
Build directory.
-
#buildpacks_for_app ⇒ Object
Buildpacks detected for the app, if any.
-
#call ⇒ Object
Launch the full packaging procedure.
-
#check ⇒ Object
Check configuration, and verifies that the current distribution’s requirements are satisfied.
-
#compile ⇒ Object
Pass the app through the buildpack.
-
#compile_cache_dir ⇒ Object
Directory where the buildpacks can store stuff.
-
#compile_env_dir ⇒ Object
Directory where the buildpacks can store config envs.
- #config_file ⇒ Object
-
#distribution ⇒ Object
Returns the current distribution we’re packaging for.
-
#extract ⇒ Object
Extract the given tarball to the target directory.
- #fpm_command ⇒ Object
-
#initialize(tarball, config) ⇒ Builder
constructor
Accepts a path to a tarball (gzipped or not), or you can pass ‘-’ to read from stdin.
-
#package(remaining_attempts = 3) ⇒ Object
Launch the FPM command that will generate the package.
- #pipeline ⇒ Object
-
#proc_dir ⇒ Object
Directory where binstubs will be created for the corresponding Procfile commands.
-
#procfile ⇒ Object
Returns the path to the app’s (supposedly present) Procfile.
- #procfile_entries ⇒ Object
-
#release_file ⇒ Object
Path to the release file generated after the buildpack compilation.
- #scaling_dir ⇒ Object
-
#setup ⇒ Object
Setup the build directory structure.
-
#setup_crons ⇒ Object
Write cron files.
- #setup_pipeline ⇒ Object
-
#source_dir ⇒ Object
Path to the directory containing the main app files.
- #store_cache ⇒ Object
-
#teardown ⇒ Object
Make sure to get rid of the build directory.
-
#update_config ⇒ Object
Update existing config with the one from .pkgr.yml file, if any.
- #vendor_dir ⇒ Object
- #verify ⇒ Object
-
#write_env ⇒ Object
Parses the output of buildpack/bin/release executable to find out its default Procfile commands.
-
#write_init ⇒ Object
Write startup scripts.
Constructor Details
#initialize(tarball, config) ⇒ Builder
Accepts a path to a tarball (gzipped or not), or you can pass ‘-’ to read from stdin.
15 16 17 18 19 |
# File 'lib/pkgr/builder.rb', line 15 def initialize(tarball, config) @tarball = tarball @config = config Pkgr.debug "Initializing builder with the following config: #{config.inspect}" end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
12 13 14 |
# File 'lib/pkgr/builder.rb', line 12 def config @config end |
#tarball ⇒ Object (readonly)
Returns the value of attribute tarball.
12 13 14 |
# File 'lib/pkgr/builder.rb', line 12 def tarball @tarball end |
Instance Method Details
#app_home_dir ⇒ Object
Some buildpacks may need the target home dir to exist
272 273 274 |
# File 'lib/pkgr/builder.rb', line 272 def app_home_dir config.home end |
#build_dir ⇒ Object
Build directory. Will be used by fpm to make the package.
249 250 251 |
# File 'lib/pkgr/builder.rb', line 249 def build_dir @build_dir ||= Dir.mktmpdir end |
#buildpacks_for_app ⇒ Object
Buildpacks detected for the app, if any. If multiple buildpacks are explicitly specified, all are used
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/pkgr/builder.rb', line 292 def buildpacks_for_app raise "#{source_dir} does not exist" unless File.directory?(source_dir) @buildpacks_for_app ||= begin mode, buildpacks = distribution.buildpacks case mode when :custom buildpacks.find_all do |buildpack| buildpack.setup(config.edge, config.home) buildpack.detect(source_dir) end else [buildpacks.find do |buildpack| buildpack.setup(config.edge, config.home) buildpack.detect(source_dir) end].compact end end end |
#call ⇒ Object
Launch the full packaging procedure
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/pkgr/builder.rb', line 22 def call extract update_config check setup setup_pipeline compile write_env write_init setup_crons package store_cache ensure teardown if config.clean end |
#check ⇒ Object
Check configuration, and verifies that the current distribution’s requirements are satisfied
88 89 90 91 |
# File 'lib/pkgr/builder.rb', line 88 def check raise Errors::ConfigurationInvalid, config.errors.join("; ") unless config.valid? distribution.check end |
#compile ⇒ Object
Pass the app through the buildpack
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/pkgr/builder.rb', line 109 def compile begin FileUtils.mkdir_p(app_home_dir) rescue Errno::EACCES => e Pkgr.logger.warn "Can't create #{app_home_dir.inspect}, which may be needed by some buildpacks." end FileUtils.mkdir_p(compile_cache_dir) FileUtils.mkdir_p(compile_env_dir) if buildpacks_for_app.size > 0 run_hook config.before_hook buildpacks_for_app.each do |buildpack| puts "-----> #{buildpack.} app" buildpack.compile(source_dir, compile_cache_dir, compile_env_dir) buildpack.release(source_dir) end run_hook config.after_hook else raise Errors::UnknownAppType, "Can't find a buildpack for your app" end end |
#compile_cache_dir ⇒ Object
Directory where the buildpacks can store stuff.
277 278 279 |
# File 'lib/pkgr/builder.rb', line 277 def compile_cache_dir config.compile_cache_dir || File.join(source_dir, ".git/cache") end |
#compile_env_dir ⇒ Object
Directory where the buildpacks can store config envs.
282 283 284 |
# File 'lib/pkgr/builder.rb', line 282 def compile_env_dir config.compile_env_dir ||= Dir.mktmpdir end |
#config_file ⇒ Object
239 240 241 |
# File 'lib/pkgr/builder.rb', line 239 def config_file File.join(source_dir, ".pkgr.yml") end |
#distribution ⇒ Object
Returns the current distribution we’re packaging for.
287 288 289 |
# File 'lib/pkgr/builder.rb', line 287 def distribution @distribution ||= Distributions.current(config) end |
#extract ⇒ Object
Extract the given tarball to the target directory
39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/pkgr/builder.rb', line 39 def extract FileUtils.mkdir_p source_dir opts = {} if tarball == "-" # FIXME: not really happy with reading everything in memory opts[:input] = $stdin.read end tarball_extract = Mixlib::ShellOut.new("tar xzf #{tarball} -C #{source_dir}", opts) tarball_extract.logger = Pkgr.logger tarball_extract.run_command tarball_extract.error! end |
#fpm_command ⇒ Object
311 312 313 |
# File 'lib/pkgr/builder.rb', line 311 def fpm_command distribution.fpm_command(build_dir) end |
#package(remaining_attempts = 3) ⇒ Object
Launch the FPM command that will generate the package.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/pkgr/builder.rb', line 181 def package(remaining_attempts = 3) app_package = Mixlib::ShellOut.new(fpm_command) app_package.logger = Pkgr.logger app_package.run_command app_package.error! begin verify rescue Mixlib::ShellOut::ShellCommandFailed => e if remaining_attempts > 0 package(remaining_attempts - 1) else raise end end end |
#pipeline ⇒ Object
77 78 79 80 81 82 83 84 85 |
# File 'lib/pkgr/builder.rb', line 77 def pipeline @pipeline ||= begin components = [] unless config.wizards.empty? || config.installer == false components << Installer.new(config.installer, distribution).setup end components end end |
#proc_dir ⇒ Object
Directory where binstubs will be created for the corresponding Procfile commands.
258 259 260 |
# File 'lib/pkgr/builder.rb', line 258 def proc_dir File.join(vendor_dir, "processes") end |
#procfile ⇒ Object
Returns the path to the app’s (supposedly present) Procfile.
267 268 269 |
# File 'lib/pkgr/builder.rb', line 267 def procfile File.join(source_dir, "Procfile") end |
#procfile_entries ⇒ Object
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/pkgr/builder.rb', line 214 def procfile_entries @procfile_entries ||= begin default_process_types = YAML.load_file(release_file)["default_process_types"] default_process_types = {} unless default_process_types entries = if File.exist?(procfile) File.read(procfile).gsub("\r\n","\n").split("\n").map do |line| if line =~ /^([A-Za-z0-9_]+):\s*(.+)$/ [$1, $2] end end.compact else [] end default_process_types.merge(Hash[entries]).map{|name, command| Process.new(name, command)} end end |
#release_file ⇒ Object
Path to the release file generated after the buildpack compilation.
235 236 237 |
# File 'lib/pkgr/builder.rb', line 235 def release_file File.join(source_dir, ".release") end |
#scaling_dir ⇒ Object
262 263 264 |
# File 'lib/pkgr/builder.rb', line 262 def scaling_dir File.join(vendor_dir, "scaling") end |
#setup ⇒ Object
Setup the build directory structure
94 95 96 97 98 99 100 |
# File 'lib/pkgr/builder.rb', line 94 def setup Dir.chdir(build_dir) do distribution.templates.each do |template| template.install(config.sesame) end end end |
#setup_crons ⇒ Object
Write cron files
167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/pkgr/builder.rb', line 167 def setup_crons crons_dir = File.join("/", distribution.crons_dir) config.crons.map! do |cron_path| Cron.new(File.(cron_path, config.home), File.join(crons_dir, File.basename(cron_path))) end config.crons.each do |cron| puts "-----> [cron] #{cron.source} => #{cron.destination}" end end |
#setup_pipeline ⇒ Object
102 103 104 105 106 |
# File 'lib/pkgr/builder.rb', line 102 def setup_pipeline pipeline.each do |component| @config = component.call(config) end end |
#source_dir ⇒ Object
Path to the directory containing the main app files.
244 245 246 |
# File 'lib/pkgr/builder.rb', line 244 def source_dir File.join(build_dir, config.home) end |
#store_cache ⇒ Object
202 203 204 205 206 207 |
# File 'lib/pkgr/builder.rb', line 202 def store_cache return true unless config.store_cache generate_cache_tarball = Mixlib::ShellOut.new %{tar czf cache.tar.gz -C #{compile_cache_dir} .} generate_cache_tarball.logger = Pkgr.logger generate_cache_tarball.run_command end |
#teardown ⇒ Object
Make sure to get rid of the build directory
210 211 212 |
# File 'lib/pkgr/builder.rb', line 210 def teardown FileUtils.rm_rf(build_dir) end |
#update_config ⇒ Object
Update existing config with the one from .pkgr.yml file, if any
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/pkgr/builder.rb', line 55 def update_config if File.exist?(config_file) Pkgr.debug "Loading #{distribution.slug} from #{config_file}." @config = Config.load_file(config_file, distribution.slug).merge(config) Pkgr.debug "Found .pkgr.yml file. Updated config is now: #{config.inspect}" # update distribution config distribution.config = @config # FIXME: make Config the authoritative source of the runner config (distribution only tells the default runner) if @config.runner type, *version = @config.runner.split("-") distribution.runner = Distributions::Runner.new(type, version.join("-")) end end config.distribution = distribution config.env.variables.push("TARGET=#{distribution.target}") # useful for templates that need to read files config.source_dir = source_dir config.build_dir = build_dir end |
#vendor_dir ⇒ Object
253 254 255 |
# File 'lib/pkgr/builder.rb', line 253 def vendor_dir File.join(source_dir, "vendor", "pkgr") end |
#verify ⇒ Object
197 198 199 200 |
# File 'lib/pkgr/builder.rb', line 197 def verify return true unless config.verify distribution.verify(Dir.pwd) end |
#write_env ⇒ Object
Parses the output of buildpack/bin/release executable to find out its default Procfile commands. Then merges those with the ones from the app’s Procfile (if any). Finally, generates a binstub in vendor/pkgr/processes/ so that these commands can be called using the app’s executable.
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/pkgr/builder.rb', line 136 def write_env FileUtils.mkdir_p proc_dir procfile_entries.each do |process| process_file = File.join(proc_dir, process.name) File.open(process_file, "w+") do |f| f.puts "#!/bin/sh" f << "exec " f << process.command f << " $@" end FileUtils.chmod 0755, process_file end end |
#write_init ⇒ Object
Write startup scripts.
154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/pkgr/builder.rb', line 154 def write_init FileUtils.mkdir_p scaling_dir Dir.chdir(scaling_dir) do distribution.initializers_for(config.name, procfile_entries).each do |(process, file)| process_config = config.dup process_config.process_name = process.name process_config.process_command = process.command file.install(process_config.sesame) end end end |