Class: Pkgr::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/pkgr/builder.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tarball, config) ⇒ Builder

Accepts a path to a tarball (gzipped or not), or you can pass ‘-’ to read from stdin.



12
13
14
15
16
# File 'lib/pkgr/builder.rb', line 12

def initialize(tarball, config)
  @tarball = tarball
  @config = config
  Pkgr.debug "Initializing builder with the following config: #{config.inspect}"
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



9
10
11
# File 'lib/pkgr/builder.rb', line 9

def config
  @config
end

#tarballObject (readonly)

Returns the value of attribute tarball.



9
10
11
# File 'lib/pkgr/builder.rb', line 9

def tarball
  @tarball
end

Instance Method Details

#build_dirObject

Build directory. Will be used by fpm to make the package.



151
152
153
# File 'lib/pkgr/builder.rb', line 151

def build_dir
  @build_dir ||= Dir.mktmpdir
end

#buildpack_for_appObject

Buildpack detected for the app, if any.



189
190
191
192
193
194
195
# File 'lib/pkgr/builder.rb', line 189

def buildpack_for_app
  raise "#{source_dir} does not exist" unless File.directory?(source_dir)
  @buildpack_for_app ||= buildpacks.find do |buildpack|
    buildpack.setup(config.edge, config.home)
    buildpack.detect(source_dir)
  end
end

#buildpacksObject

List of available buildpacks for the current distribution.



184
185
186
# File 'lib/pkgr/builder.rb', line 184

def buildpacks
  distribution.buildpacks(config.buildpack)
end

#callObject

Launch the full packaging procedure



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/pkgr/builder.rb', line 19

def call
  check
  setup
  extract
  compile
  write_env
  write_init
  package
ensure
  teardown if config.clean
end

#checkObject

Check configuration, and verifies that the current distribution’s requirements are satisfied



32
33
34
35
# File 'lib/pkgr/builder.rb', line 32

def check
  raise Errors::ConfigurationInvalid, config.errors.join("; ") unless config.valid?
  distribution.check(config)
end

#compileObject

Pass the app through the buildpack



62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/pkgr/builder.rb', line 62

def compile
  if buildpack_for_app
    puts "-----> #{buildpack_for_app.banner} app"

    FileUtils.mkdir_p(compile_cache_dir)

    run_hook config.before_precompile
    buildpack_for_app.compile(source_dir, compile_cache_dir)
    buildpack_for_app.release(source_dir, compile_cache_dir)
  else
    raise Errors::UnknownAppType, "Can't find a buildpack for your app"
  end
end

#compile_cache_dirObject

Directory where the buildpacks can store stuff.



174
175
176
# File 'lib/pkgr/builder.rb', line 174

def compile_cache_dir
  config.compile_cache_dir || File.join(source_dir, ".git/cache")
end

#distributionObject

Returns the current distribution we’re packaging for.



179
180
181
# File 'lib/pkgr/builder.rb', line 179

def distribution
  @distribution ||= Distributions.current
end

#extractObject

Extract the given tarball to the target directory



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/pkgr/builder.rb', line 47

def extract
  raise "#{source_dir} does not exist" unless File.directory?(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.run_command
  tarball_extract.error!
end

#fpm_commandObject



197
198
199
# File 'lib/pkgr/builder.rb', line 197

def fpm_command
  distribution.fpm_command(build_dir, config)
end

#packageObject

Launch the FPM command that will generate the package.



108
109
110
111
112
113
# File 'lib/pkgr/builder.rb', line 108

def package
  Pkgr.info "Running command: #{fpm_command}"
  app_package = Mixlib::ShellOut.new(fpm_command)
  app_package.run_command
  app_package.error!
end

#proc_dirObject

Directory where binstubs will be created for the corresponding Procfile commands.



160
161
162
# File 'lib/pkgr/builder.rb', line 160

def proc_dir
  File.join(vendor_dir, "processes")
end

#procfileObject

Returns the path to the app’s (supposedly present) Procfile.



169
170
171
# File 'lib/pkgr/builder.rb', line 169

def procfile
  File.join(source_dir, "Procfile")
end

#procfile_entriesObject



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/pkgr/builder.rb', line 120

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_fileObject

Path to the release file generated after the buildpack compilation.



141
142
143
# File 'lib/pkgr/builder.rb', line 141

def release_file
  File.join(source_dir, ".release")
end

#scaling_dirObject



164
165
166
# File 'lib/pkgr/builder.rb', line 164

def scaling_dir
  File.join(vendor_dir, "scaling")
end

#setupObject

Setup the build directory structure



38
39
40
41
42
43
44
# File 'lib/pkgr/builder.rb', line 38

def setup
  Dir.chdir(build_dir) do
    distribution.templates(config.name).each do |template|
      template.install(config.sesame)
    end
  end
end

#source_dirObject

Path to the directory containing the main app files.



146
147
148
# File 'lib/pkgr/builder.rb', line 146

def source_dir
  File.join(build_dir, "opt/#{config.name}")
end

#teardownObject

Make sure to get rid of the build directory



116
117
118
# File 'lib/pkgr/builder.rb', line 116

def teardown
  FileUtils.rm_rf(build_dir)
end

#vendor_dirObject



155
156
157
# File 'lib/pkgr/builder.rb', line 155

def vendor_dir
  File.join(source_dir, "vendor", "pkgr")
end

#write_envObject

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.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/pkgr/builder.rb', line 79

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 << process.command
      f << " $@"
    end

    FileUtils.chmod 0755, process_file
  end
end

#write_initObject

Write startup scripts.



95
96
97
98
99
100
101
102
103
104
105
# File 'lib/pkgr/builder.rb', line 95

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