lib/slugbuilder/builder.rb in slugbuilder-1.1.0 vs lib/slugbuilder/builder.rb in slugbuilder-1.2.0
- old
+ new
@@ -9,10 +9,11 @@
@stdout = stdout
@base_dir = Slugbuilder.config.base_dir
@cache_dir = Shellwords.escape(Slugbuilder.config.cache_dir)
@output_dir = Slugbuilder.config.output_dir
@buildpacks_dir = File.join(@cache_dir, 'buildpacks')
+ @env_dir = File.join(@base_dir, 'environment')
@repo = repo
@git_ref = git_ref
@git_dir = Shellwords.escape(File.join(@base_dir, 'git', repo))
@build_dir = Shellwords.escape(File.join(@base_dir, repo, git_ref))
@@ -22,18 +23,25 @@
yield(repo: repo, git_ref: git_ref)
end
end
def build(clear_cache: false, env: {}, prebuild: nil, postbuild: nil, slug_name: nil, buildpacks: Slugbuilder.config.buildpacks)
+ @old_env = ENV.to_h
+ # clear environment from previous builds
+ FileUtils.rm_rf(@env_dir)
+ FileUtils.mkdir_p(@env_dir)
+
@buildpacks = buildpacks
@env = env
@slug_file = slug_name ? "#{slug_name}.tgz" : Shellwords.escape("#{@repo.gsub('/', '.')}.#{@git_ref}.#{@git_sha}.tgz")
wipe_cache if clear_cache
prebuild.call(repo: @repo, git_ref: @git_ref) if prebuild
- build_and_release
+ with_clean_env do
+ build_and_release
+ end
stitle("Setup completed in #{@setup_time} seconds")
stitle("Build completed in #{@build_time} seconds")
stext("Application compiled in #{@compile_time} seconds")
stext("Slug compressed in #{@slug_time} seconds")
stitle("Slug built to #{File.join(@output_dir, @slug_file)}")
@@ -43,26 +51,39 @@
compile: @compile_time,
slug: @slug_time,
output: build_output.join('')
}
- postbuild.call(repo: @repo, git_ref: @git_ref, git_sha: @git_sha, stats: stats, slug: File.join(@output_dir, @slug_file)) if postbuild
+ postbuild.call(repo: @repo, git_ref: @git_ref, git_sha: @git_sha, request_id: @request_id, stats: stats, slug: File.join(@output_dir, @slug_file)) if postbuild
if block_given?
- yield(repo: @repo, git_ref: @git_ref, git_sha: @git_sha, stats: stats, slug: File.join(@output_dir, @slug_file))
+ yield(repo: @repo, git_ref: @git_ref, git_sha: @git_sha, request_id: @request_id, stats: stats, slug: File.join(@output_dir, @slug_file))
end
return true
rescue => e
- stitle("Failed: #{e}")
+ stitle("Failed: #{e}\n#{e.backtrace.join("\n")}")
return false
+ ensure
+ restore_env
end
private
+ def restore_env
+ ENV.delete_if { true }
+ ENV.update(@old_env)
+ end
+
+ def with_clean_env
+ ENV.delete_if { true }
+ yield
+ restore_env
+ end
+
def wipe_cache
FileUtils.rm_rf(@cache_dir)
- FileUtils.mkdir_p(File.join(@cache_dir, 'buildpacks'))
+ FileUtils.mkdir_p(@buildpacks_dir)
end
def build_and_release
@build_time = realtime do
set_environment
@@ -92,14 +113,16 @@
def set_environment
load_env_file("#{@cache_dir}/env")
load_env_file("#{@build_dir}/.env")
ENV['STACK'] = 'cedar-14'
+ @request_id = SecureRandom.urlsafe_base64(32)
+ ENV['REQUEST_ID'] = @request_id
+ ENV['SOURCE_VERSION'] = @git_sha
- @env.each do |k, v|
- ENV[k.to_s] = v.to_s
- end
+ # write user envs to files
+ write_user_envs(@env)
ENV['HOME'] = @build_dir
ENV['APP_DIR'] = @build_dir
stitle('Build environment')
@@ -108,30 +131,30 @@
end
end
def create_dirs
FileUtils.mkdir_p(@base_dir)
- FileUtils.mkdir_p(File.join(@cache_dir, 'buildpacks'))
+ FileUtils.mkdir_p(@buildpacks_dir)
FileUtils.mkdir_p(@output_dir)
# clear old build
FileUtils.rm_rf(@build_dir)
FileUtils.mkdir_p(File.join(@build_dir, '.profile.d'))
end
def checkout_git_ref
Dir.chdir(@git_dir) do
# checkout branch or sha
# get branch from origin so it is always the most recent
- rc = run("git fetch --all && (git checkout origin/#{@git_ref} || git checkout #{@git_ref}) 2>&1")
+ rc = run("git fetch --quiet --all && (git checkout --quiet origin/#{@git_ref} || git checkout --quiet #{@git_ref})")
fail "Failed to fetch and checkout: #{@git_ref}" if rc != 0
@git_sha = `git rev-parse HEAD`.strip
end
end
def download_repo
stitle("Fetching #{@repo}")
- rc = run("git clone git@#{Slugbuilder.config.git_service}:#{@repo}.git #{@git_dir} 2>&1")
+ rc = run("git clone --quiet git@#{Slugbuilder.config.git_service}:#{@repo}.git #{@git_dir}")
fail "Failed to download repo: #{@repo}" if rc != 0
end
def copy_app
# copy dotfiles but not .git, ., or ..
@@ -151,17 +174,17 @@
@buildpacks.each do |buildpack_url|
buildpack_name = get_buildpack_name(buildpack_url)
if !existing_buildpacks.include?(buildpack_name)
# download buildpack
stitle("Fetching buildpack: #{buildpack_name}")
- rc = run("git clone --depth=1 #{buildpack_url} #{@buildpacks_dir}/#{buildpack_name} 2>&1")
+ rc = run("git clone --quiet --depth=1 #{buildpack_url} #{@buildpacks_dir}/#{buildpack_name}")
fail "Failed to download buildpack: #{buildpack_name}" if rc != 0
else
# fetch latest
stitle("Using cached buildpack. Ensuring latest version of buildpack: #{buildpack_name}")
Dir.chdir("#{@buildpacks_dir}/#{buildpack_name}") do
- rc = run('git pull 2>&1')
+ rc = run('git pull --quiet')
fail "Failed to update: #{buildpack_name}" if rc != 0
end
end
end
@@ -174,25 +197,29 @@
buildpacks.each do |buildpack_url|
buildpack_name = get_buildpack_name(buildpack_url)
buildpack = File.join(@buildpacks_dir, buildpack_name)
if run("#{buildpack}/bin/detect #{@build_dir}") == 0
@compile_time += realtime { compile(buildpack) }
+
+ # load environment for subsequent buildpacks
+ load_export_env(File.join(buildpack, 'export'))
+
release(buildpack)
end
end
end
def compile(buildpack)
- rc = run_echo("#{buildpack}/bin/compile '#{@build_dir}' '#{@cache_dir}'")
+ rc = run_echo("#{buildpack}/bin/compile '#{@build_dir}' '#{@cache_dir}' '#{@env_dir}'")
fail "Couldn't compile application using buildpack #{buildpack}" if rc != 0
end
def release(buildpack)
# should create .release
release_file = File.open("#{@build_dir}/.release", 'w')
- rc = run("#{buildpack}/bin/release '#{@build_dir}' '#{@cache_dir}'") do |line|
+ rc = run("#{buildpack}/bin/release '#{@build_dir}'") do |line|
release_file.print(line)
end
release_file.close
fail "Couldn't compile application using buildpack #{buildpack}" if rc != 0
@@ -265,20 +292,42 @@
build_output << line
@stdout.print(line)
end
end
+ def load_export_env(file)
+ if File.exists?(file)
+ exports = IO.read(file).split('export')
+ exports.each do |line|
+ parts = line.split(/=/, 2)
+ next if parts.length != 2
+ name, val = parts
+ name.strip!
+ val = val.strip.split(/\n/).join.gsub('"', '')
+
+ ENV[name] = `echo "#{val}"`.strip
+ end
+ end
+ end
+
+ def write_user_envs(envs)
+ envs.each do |key, val|
+ File.open(File.join(@env_dir, key.to_s), 'w') do |file|
+ file.write(val.to_s)
+ end
+ end
+ end
+
def load_env_file(file)
if File.exists?(file)
new_envs = IO.readlines(file)
new_envs.each do |line|
line.strip!
next if line.match(/^#/)
parts = line.split(/=/, 2)
next if parts.length != 2
- ENV[parts[0]] = parts[1]
@env[parts[0]] = parts[1]
end
end
end
end