class FPM::Fry::Command::Cook
Constants
- UPDATE_VALUES
Attributes
build_image[W]
builder[W]
cache[W]
image_id[W]
output_class[W]
Public Class Methods
new(invocation_path, ctx = {}, parent_attribute_values = {})
click to toggle source
Calls superclass method
FPM::Fry::Command::new
# File lib/fpm/fry/command/cook.rb, line 22 def initialize(invocation_path, ctx = {}, parent_attribute_values = {}) @tls = nil require 'digest' require 'fileutils' require 'fpm/fry/with_data' require 'fpm/fry/recipe' require 'fpm/fry/recipe/builder' require 'fpm/fry/detector' require 'fpm/fry/docker_file' require 'fpm/fry/stream_parser' require 'fpm/fry/block_enumerator' require 'fpm/fry/build_output_parser' require 'fpm/fry/inspector' require 'fpm/fry/plugin/config' super end
Public Instance Methods
adjust_config_files( output )
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 374 def adjust_config_files( output ) # FPM flags all files in /etc as config files but only for debian :/. # Actually this behavior makes sense to me for all packages because it's # the thing I usually want. By setting this attribute at least the # misleading warning goes away. output.attributes[:deb_no_default_config_files?] = true output.attributes[:deb_auto_config_files?] = false return if output.attributes[:fry_config_explicitly_used] # Now that we have disabled this for debian we have to reenable if it for # all. etc = File.expand_path('etc', output.staging_path) if File.exist?( etc ) # Config plugin wasn't used. Add everything under /etc prefix_length = output.staging_path.size + 1 added = [] Find.find(etc) do | path | next unless File.file? path name = path[prefix_length..-1] if !output.config_files.include? name added << name output.config_files << name end end if added.any? logger.hint( "#{output.name} contains some config files in /etc. They were automatically added. You can customize this using the \"config\" plugin.", documentation: "https://github.com/xing/fpm-fry/wiki/Plugin-config", files: added) end end end
adjust_package_architecture(output)
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 362 def adjust_package_architecture(output) # strip prefix and only use the architecture part output.architecture = platform.split("/").last if platform end
adjust_package_settings( output )
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 367 def adjust_package_settings( output ) # FPM ignores the file permissions on rpm packages. output.attributes[:rpm_use_file_permissions?] = true output.attributes[:rpm_user] = 'root' output.attributes[:rpm_group] = 'root' end
build!() { |container| ... }
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 206 def build! body = begin url = client.url('containers','create') args = { headers: { 'Content-Type' => 'application/json' }, path: url, expects: [201], body: JSON.generate({"Image" => build_image}) } args[:query] = { platform: platform } if platform res = client.post(args) JSON.parse(res.body) rescue Excon::Error logger.error "could not create #{build_image}, url: #{url}" raise end container = body['Id'] begin begin url = client.url('containers',container,'start') client.post( headers: { 'Content-Type' => 'application/json' }, path: url, expects: [204], body: JSON.generate({}) ) rescue Excon::Error logger.error "could not start container #{container}, url: #{url}" raise end begin url = client.url('containers',container,'attach?stderr=1&stdout=1&stream=1&logs=1') client.post( path: url, body: '', expects: [200], middlewares: [ StreamParser.new(out,err), Excon::Middleware::Expects, Excon::Middleware::Instrumentor, Excon::Middleware::Mock ] ) rescue Excon::Error logger.error "could not attach to container #{container}, url: #{url}" raise end begin res = client.post( path: client.url('containers',container,'wait'), expects: [200], body: '' ) json = JSON.parse(res.body) if json["StatusCode"] != 0 raise Fry::WithData("Build failed", exit_code: json["StatusCode"]) end rescue Excon::Error logger.error "could not wait successfully for container #{container}, url: #{url}" raise end yield container ensure unless keep? client.destroy(container) end end end
build_image()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 112 def build_image @build_image ||= begin sum = Digest::SHA256.hexdigest( image_id + "\0" + cache.cachekey ) cachetag = "fpm-fry:#{sum[0..30]}" res = begin url = client.url("images/#{cachetag}/json") client.get( expects: [200,404], path: url ) rescue Excon::Error logger.error "could not fetch image json for #{image}, url: #{url}" raise end if res.status == 404 df = DockerFile::Source.new(builder.variables.merge(image: image_id),cache) begin url = client.url("build") query = { rm: 1, dockerfile: DockerFile::NAME, t: cachetag } query[:platform] = platform if platform client.post( headers: { 'Content-Type'=>'application/tar' }, query: query, expects: [200], path: url, request_block: BlockEnumerator.new(df.tar_io) ) rescue Excon::Error logger.error "could not build #{image}, url: #{url}" raise end else # Hack to trigger hints/warnings even when the cache is valid. DockerFile::Source.new(builder.variables.merge(image: image_id),cache).send(:file_map) end df = DockerFile::Build.new(cachetag, builder.variables.dup,builder.recipe, update: update?) parser = BuildOutputParser.new(out) begin url = client.url("build") query = { rm: 1, dockerfile: DockerFile::NAME} query[:platform] = platform if platform res = client.post( headers: { 'Content-Type'=>'application/tar' }, query: query, expects: [200], path: url, request_block: BlockEnumerator.new(df.tar_io), response_block: parser ) rescue Excon::Error logger.error "could not build #{image}, url: #{url}" raise end if parser.images.none? raise "Didn't find a build image in the stream. This usually means that the build script failed." end image = parser.images.last logger.debug("Detected build image", image: image) image end end
builder()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 56 def builder @builder ||= begin b = nil Inspector.for_image(client, image) do |inspector| variables = Detector.detect(inspector) variables[:architecture] = platform logger.debug("Loading recipe",variables: variables, recipe: recipe) b = Recipe::Builder.new(variables, logger: ui.logger, inspector: inspector) b.load_file( recipe ) end b end end
cache()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 75 def cache @cache ||= builder.recipe.source.build_cache(tmpdir) end
execute()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 409 def execute # force some eager loading lint_recipe_file! builder lint_output_class! lint_recipe! cache image_id build_image packages do | dir_map | build! do |container| input_package(container) do |input| input.split( container, dir_map ) end end end return 0 rescue Recipe::NotFound => e logger.error("Recipe not found", recipe: recipe, exception: e) return 1 rescue => e logger.error(e) return 1 end
flavour()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 71 def flavour builder.variables[:flavour] end
image_id()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 98 def image_id @image_id ||= begin url = client.url("images/#{image}/json") res = client.get(expects: [200], path: url) body = JSON.parse(res.body) body.fetch('id'){ body.fetch('Id') } rescue Excon::Error logger.error "could not fetch image json for #{image}, url: #{url}" raise end end
input_package(container) { |input| ... }
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 282 def input_package(container) input = FPM::Package::Docker.new( logger: logger, client: client, keep_modified_files: builder.keep_modified_files, verbose: verbose, ) builder.recipe.apply_input(input) begin input.input(container) return yield(input) ensure input.cleanup_staging input.cleanup_build end end
lint_output_class!()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 80 def lint_output_class! end
lint_recipe!()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 88 def lint_recipe! problems = builder.recipe.lint if problems.any? problems.each do |p| logger.error(p) end raise end end
lint_recipe_file!()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 84 def lint_recipe_file! File.exist?(recipe) || raise(Recipe::NotFound) end
output_class()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 39 def output_class @output_class ||= begin logger.debug("Autodetecting package type",flavour: flavour) case(flavour) when 'debian' require 'fpm/package/deb' FPM::Package::Deb when 'redhat' require 'fpm/package/rpm' FPM::Package::RPM else raise "Cannot auto-detect package type." end end end
packages() { |dir_map| ... }
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 325 def packages dir_map = [] out_map = {} builder.recipe.packages.each do | package | output = output_class.new output.instance_variable_set(:@logger,logger) package.files.each do | pattern | dir_map << [ pattern, output.staging_path ] end out_map[ output ] = package end dir_map = Hash[ dir_map.reverse ] yield dir_map out_map.each do |output, package| package.apply_output(output) adjust_package_architecture(output) adjust_package_settings(output) adjust_config_files(output) end out_map.each do |output, _| write_output!(output) end ensure out_map.each do |output, _| output.cleanup_staging output.cleanup_build end end
update?()
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 180 def update? if flavour == 'debian' case(update) when 'auto' Inspector.for_image(client, image) do |inspector| begin inspector.read('/var/lib/apt/lists') do |file| next if file.header.name == 'lists/' logger.hint("/var/lib/apt/lists is not empty, you could try to speed up builds with --update=never", documentation: 'https://github.com/xing/fpm-fry/wiki/The-update-parameter') break end rescue FPM::Fry::Client::FileNotFound logger.hint("/var/lib/apt/lists does not exists, so we will autoupdate") end end return true when 'always' return true when 'never' return false end else return false end end
write_output!(output)
click to toggle source
# File lib/fpm/fry/command/cook.rb, line 299 def write_output!(output) package_file = File.expand_path(output.to_s(nil)) FileUtils.mkdir_p(File.dirname(package_file)) tmp_package_file = package_file + '.tmp' begin FileUtils.rm_rf tmp_package_file rescue Errno::ENOENT end output.output(tmp_package_file) if output.config_files.any? logger.debug("Found config files for #{output.name}", files: output.config_files) else logger.debug("No config files for #{output.name}") end begin FileUtils.rm_rf package_file rescue Errno::ENOENT end File.rename tmp_package_file, package_file logger.info("Created package", :path => package_file) end