Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use habitat build instead of omnibus #107

Merged
merged 9 commits into from
Feb 3, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 114 additions & 120 deletions bin/appbundle-updater
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,43 @@ require "rubygems/package"
require "zlib"
require "tempfile"

# FIXME: move to helpers mixin

def windows?
@windows ||= RUBY_PLATFORM =~ /mswin|mingw|windows/
end

def chefdk
def habitat
if windows?
Pathname.new(File.join(ENV["SYSTEMDRIVE"], "opscode", ARGV[0]))
Pathname.new(File.join(ENV["SYSTEMDRIVE"], "hab", "pkgs"))
else
Pathname.new(File.join("/opt", ARGV[0]))
Pathname.new(File.join("/hab", "pkgs"))
end
end

# find the path to installed package in habitat package directory
# example, /hab/pkgs/{ARGV[0]}/{ARGV[1]}/x.x.x/xxxxxxxxxxxxxx
def pkg_path
pkg_path = habitat.join(ARGV[0], ARGV[1])
version = Dir.glob("#{pkg_path}/*").max
raise "No existing installation found for #{ARGV[0]}/#{ARGV[1]} in #{pkg_path}" if version.nil?

pkg_path = pkg_path.join(version)
build_no = Dir.glob("#{pkg_path}/*").max
raise "No existing installation found for #{ARGV[0]}/#{ARGV[1]}/#{version} in #{pkg_path}" if build_no.nil?

pkg_path.join(build_no)
end

def vendor_bin_dir
pkg_path.join("vendor", "bin")
end

def bin_dir
chefdk.join("embedded/bin")
pkg_path.join("bin")
end

def ruby_pkg
# NOTE: this is sort of a 'hacky' way maybe to find which ruby binary to use?
File.read("#{pkg_path}/DEPS").split("\n").find { |l| l.start_with?(%r{(core|chef)\/ruby}) }
end

ENV["PATH"] = ( [ bin_dir ] + ENV["PATH"].split(File::PATH_SEPARATOR) ).join(File::PATH_SEPARATOR)
Expand All @@ -50,7 +71,7 @@ ENV_KEYS = %w{

def run(cmd)
ENV_KEYS.each { |key| ENV["_YOLO_#{key}"] = ENV[key]; ENV.delete(key) }
ENV["PATH"] = bin_dir.to_s + File::PATH_SEPARATOR + ENV["_YOLO_PATH"]
ENV["PATH"] = habitat.join(ruby_pkg, "bin").to_s + File::PATH_SEPARATOR + ENV["_YOLO_PATH"]
puts " running: #{cmd}"
output = `#{cmd} 2>&1` # FIXME: bash/zsh-ism, will not work on csh
unless $?.exited? && $?.exitstatus == 0
Expand All @@ -66,7 +87,7 @@ TAR_LONGLINK = "././@LongLink".freeze

def install_package_dependencies
banner("Installing Packages")
case `#{bin_dir}/ohai platform_family` # rubocop: disable Lint/LiteralAsCondition
case `hab pkg exec #{ARGV[0]}/#{ARGV[1]} ohai platform_family` # rubocop: disable Lint/LiteralAsCondition
when /debian/
ENV["DEBIAN_FRONTEND"] = "noninteractive"
run("apt-get -y update")
Expand Down Expand Up @@ -118,7 +139,7 @@ def extract_tgz(file, destination = ".")
end
end

App = Struct.new(:name, :repo, :bundle_without, :install_commands, :gems) do
App = Struct.new(:name, :origin, :bundle_without, :install_commands, :gems) do
def initialize(*)
super
self.gems ||= {}
Expand All @@ -129,18 +150,18 @@ App = Struct.new(:name, :repo, :bundle_without, :install_commands, :gems) do
end
end

chef_install_command = "#{bin_dir.join("rake")} install:local"
chef_install_command = "#{vendor_bin_dir.join("rake")} install:local"

CHEFDK_APPS = [
HABITAT_PACKAGES = [
App.new(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we're using chef/berkshelf for the remnant of this usage.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the origin to chef in 6ee4d26. Updated the origin for other packages as well.

"berkshelf",
"berkshelf/berkshelf",
"chef",
"docs changelog",
"#{bin_dir.join("rake")} install"
"#{vendor_bin_dir.join("rake")} install"
),
App.new(
"chef-infra-client",
"chef",
"chef/chef",
"server docgen maintenance pry integration ci chefstyle profile",
chef_install_command,
{
Expand All @@ -150,67 +171,40 @@ CHEFDK_APPS = [
"inspec-core-bin" => %w{development},
}
),
App.new(
"chef-dk",
"chef/chef-dk",
"development test",
"#{bin_dir.join("bundle")} install",
{
"chef" => %w{docgen chefstyle omnibus_package},
"foodcritic" => %w{development test},
"test-kitchen" => %w{changelog debug docs development},
"inspec" => %w{deploy tools maintenance integration},
"chef-run" => %w{changelog docs debug},
"chef-cli" => %w{changelog docs debug},
"berkshelf" => %w{changelog docs debug development},
"chef-bin" => %w{changelog},
"chef-apply" => %w{changelog},
"chef-vault" => %w{changelog},
"ohai" => %w{changelog},
"opscode-pushy-client" => %w{changelog},
"cookstyle" => %w{changelog},
}
),
App.new(
"chef-vault",
"chef/chef-vault",
"chef",
"development",
"#{bin_dir.join("rake")} install"
"#{vendor_bin_dir.join("rake")} install"
),
App.new(
"cookstyle",
"chef/cookstyle",
"chef",
"development debug docs",
"#{bin_dir.join("rake")} install"
),
App.new(
"foodcritic",
"foodcritic/foodcritic",
"development",
"#{bin_dir.join("rake")} install"
"#{vendor_bin_dir.join("rake")} install"
),
App.new(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove foodcritic

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed in 6ee4d26

"inspec",
"chef/inspec",
"chef",
"test integration tools maintenance deploy",
"#{bin_dir.join("rake")} install"
"#{vendor_bin_dir.join("rake")} install"
),
App.new(
"ohai",
"chef/ohai",
"chef",
"development docs debug",
"#{bin_dir.join("rake")} install"
"#{vendor_bin_dir.join("rake")} install"
),
App.new(
"test-kitchen",
"test-kitchen/test-kitchen",
"chef",
"changelog integration debug chefstyle docs",
"#{bin_dir.join("rake")} install"
"#{vendor_bin_dir.join("rake")} install"
),
].freeze

class Updater
attr_reader :app, :ref, :tarball, :repo, :gems, :install_commands
attr_reader :app, :ref, :tarball, :origin, :repo, :gems, :install_commands

def initialize(options)
@app = options[:app]
Expand All @@ -219,6 +213,7 @@ class Updater
@extra_bin_files = options[:extra_bin_files]
@binstubs_source = options[:binstubs_source]
@repo = options[:repo] || @app.repo
@origin = options[:origin] || @app.origin
@gems = @app.gems
@install_commands = @app.install_commands
end
Expand All @@ -228,101 +223,100 @@ class Updater
abort "#{$0} needs to be run as root user or with sudo"
end

banner("Cleaning #{app} checkout")
app_dir.rmtree if app_dir.directory?

top_dir = chefdk.join("embedded/apps")
unless File.exist?(top_dir)
banner("Creating #{top_dir} directory")
FileUtils.mkdir_p top_dir
end

install_package_dependencies

if tarball
# NOTE: THIS IS DELIBERATELY PURE RUBY USING NO NATIVE GEMS AND ONLY
# THE RUBY STDLIB BY DESIGN
git_url = "https://github.com/#{repo}/archive/#{ref}.tar.gz"
banner("Extracting #{app} from #{git_url}")
Dir.chdir(chefdk.join("embedded/apps")) do
Tempfile.open("appbundle-updater") do |tempfile|
tempfile.binmode
URI.open(git_url) do |uri|
tempfile.write(uri.read)
tmp_dir = Dir.mktmpdir
banner("Creating #{tmp_dir}/#{app.name} directory")
app_dir = File.join(tmp_dir, app.name.to_s)

begin
if tarball
# NOTE: THIS IS DELIBERATELY PURE RUBY USING NO NATIVE GEMS AND ONLY
# THE RUBY STDLIB BY DESIGN
git_url = "https://github.com/#{repo}/archive/#{ref}.tar.gz"
banner("Extracting #{app} from #{git_url}")
Dir.chdir(tmp_dir) do
Tempfile.open("appbundle-updater") do |tempfile|
tempfile.binmode
URI.open(git_url) do |uri|
tempfile.write(uri.read)
end
tempfile.close
extract_tgz(tempfile.path)
end
tempfile.close
extract_tgz(tempfile.path)
base = File.basename repo
FileUtils.mv Dir.glob("#{base}-*")[0], app.name.to_s
end
else
git_url = "https://github.com/#{repo}.git"
banner("Cloning #{app} from #{git_url}")
run("git clone #{git_url} #{app_dir}")

banner("Checking out #{app} to #{ref}")
Dir.chdir(app_dir) do
run("git checkout #{ref}")
end
base = File.basename repo
FileUtils.mv Dir.glob("#{base}-*")[0], "#{app.name}"
end
else
git_url = "https://github.com/#{repo}.git"
banner("Cloning #{app} from #{git_url}")
run("git clone #{git_url} #{app_dir}")

banner("Checking out #{app} to #{ref}")
banner("Installing dependencies")
Dir.chdir(app_dir) do
run("git checkout #{ref}")
cmd = "#{vendor_bin_dir.join("bundle")} install"
cmd += " --without #{app.bundle_without}" if app.bundle_without
ruby(cmd)
end
end

banner("Installing dependencies")
Dir.chdir(app_dir) do
cmd = "#{bin_dir.join("bundle")} install"
cmd += " --without #{app.bundle_without}" if app.bundle_without
ruby(cmd)
end

banner("Re-installing git-installed gems")
Dir.chdir(app_dir) do
ruby("post-bundle-install.rb #{chefdk}") if File.exist?("#{app_dir}/post-bundle-install.rb")
end

banner("Installing gem")
Dir.chdir(app_dir) do
Array(install_commands).each do |command|
ruby(command)
banner("Re-installing git-installed gems")
Dir.chdir(app_dir) do
ruby("post-bundle-install.rb #{bin_dir}") if File.exist?("#{app_dir}/post-bundle-install.rb")
end
end

banner("Updating appbundler binstubs for #{app}")
if gems.empty?
banner("Installing gem")
Dir.chdir(app_dir) do
cmd = "#{bin_dir.join("appbundler")} #{app_dir} #{chefdk.join("bin")}"
cmd += " --extra-bin-files #{@extra_bin_files}" if @extra_bin_files
cmd += " --binstubs-source #{@binstubs_source}" if @binstubs_source
ruby(cmd)
Array(install_commands).each do |command|
ruby(command)
end
end
else
gems.each do |gem_name, without|

banner("Updating appbundler binstubs for #{app}")
if gems.empty?
Dir.chdir(app_dir) do
cmd = "#{bin_dir.join("appbundler")} #{app_dir} #{chefdk.join("bin")} #{gem_name}"
cmd += " --without #{without.join(",")}" if without
cmd = "#{vendor_bin_dir.join("appbundler")} #{app_dir} #{bin_dir}"
cmd += " --extra-bin-files #{@extra_bin_files}" if @extra_bin_files
cmd += " --binstubs-source #{@binstubs_source}" if @binstubs_source
ruby(cmd)
end
else
gems.each do |gem_name, without|
Dir.chdir(app_dir) do
cmd = "#{vendor_bin_dir.join("appbundler")} #{app_dir} #{bin_dir} #{gem_name}"
cmd += " --without #{without.join(",")}" if without
cmd += " --extra-bin-files #{@extra_bin_files}" if @extra_bin_files
cmd += " --binstubs-source #{@binstubs_source}" if @binstubs_source
ruby(cmd)
end
end
end
end

banner("Finished!")
rescue => e
puts "aborting!!", e
else
banner("Finished!")
ensure
banner("Cleaning up #{app_dir}")
FileUtils.remove_entry app_dir
banner("Done.")
end
end

private

def app_dir
chefdk.join("embedded/apps/#{app}")
end

def banner(msg)
puts "-----> #{msg}"
end

def ruby(script)
ruby = bin_dir.join("ruby").to_s.tap { |p| p.concat(".exe") if windows? }

run([ruby, script].join(" "))
ruby_cmd = "hab pkg exec #{ruby_pkg} ruby"
run([ruby_cmd, script].join(" "))
end

end
Expand Down Expand Up @@ -356,15 +350,15 @@ class CLI
end
opts.separator("")
opts.separator("App names:")
CHEFDK_APPS.each { |a| opts.separator(" * #{a.name}") }
HABITAT_PACKAGES.each { |a| opts.separator(" * #{a.name}") }
end
@parser.parse!
validate!
end

def validate!
die("PROJECT APP_NAME GIT_REF options are all required") if ARGV.length < 3
options[:app] = CHEFDK_APPS.find { |a| a.name == ARGV[1] }
options[:app] = HABITAT_PACKAGES.find { |a| a.name == ARGV[1] }
die("Invalid APP_NAME: #{ARGV[1]}") if options[:app].nil?
options[:ref] = ARGV[2]
end
Expand Down