diff --git a/Gemfile b/Gemfile index 7461ea33..35c31929 100644 --- a/Gemfile +++ b/Gemfile @@ -19,10 +19,13 @@ group :development do gem "pry" gem "pry-byebug" gem "rb-readline" + gem "appbundler" end group :profile do - gem "stackprof" - gem "stackprof-webnav" - gem "memory_profiler" -end + unless RUBY_PLATFORM.match?(/mswin|mingw|windows/) + gem "stackprof" + gem "stackprof-webnav" + gem "memory_profiler" + end +end \ No newline at end of file diff --git a/Rakefile b/Rakefile index 3b92ac1a..f25cfd7f 100644 --- a/Rakefile +++ b/Rakefile @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# +require "bundler/gem_tasks" namespace :style do begin @@ -52,3 +54,4 @@ namespace :style do puts ">>> Gem load error: #{e}, omitting #{task.name}" unless ENV["CI"] end end + diff --git a/habitat/plan.sh b/habitat/plan.sh new file mode 100644 index 00000000..4cb5abbc --- /dev/null +++ b/habitat/plan.sh @@ -0,0 +1,122 @@ +_chef_client_ruby="core/ruby31" +pkg_name="chef-cli" +pkg_origin="ngupta26" +pkg_maintainer="The Chef Maintainers " +pkg_description="The Chef CLI" +pkg_license=('Apache-2.0') +pkg_bin_dirs=( + bin + vendor/bin +) +pkg_build_deps=( + core/make + core/gcc + core/git + core/libarchive +) +pkg_deps=( + $_chef_client_ruby + core/coreutils +) +pkg_svc_user=root + +pkg_version() { + cat "${SRC_PATH}/VERSION" +} + +do_before() { + do_default_before + update_pkg_version + # We must wait until we update the pkg_version to use the pkg_version + pkg_filename="${pkg_name}-${pkg_version}.tar.gz" +} + +do_download() { + build_line "Locally creating archive of latest repository commit at ${HAB_CACHE_SRC_PATH}/${pkg_filename}" + # source is in this repo, so we're going to create an archive from the + # appropriate path within the repo and place the generated tarball in the + # location expected by do_unpack + ( cd "${SRC_PATH}" || exit_with "unable to enter hab-src directory" 1 + git archive --prefix="${pkg_name}-${pkg_version}/" --output="${HAB_CACHE_SRC_PATH}/${pkg_filename}" HEAD + ) +} + +do_verify() { + build_line "Skipping checksum verification on the archive we just created." + return 0 +} + +do_setup_environment() { + push_runtime_env GEM_PATH "${pkg_prefix}/vendor" + + set_runtime_env APPBUNDLER_ALLOW_RVM "true" # prevent appbundler from clearing out the carefully constructed runtime GEM_PATH + set_runtime_env LANG "en_US.UTF-8" + set_runtime_env LC_CTYPE "en_US.UTF-8" +} + +do_prepare() { + export GEM_HOME="${pkg_prefix}/vendor" + export CPPFLAGS="${CPPFLAGS} ${CFLAGS}" + + ( cd "$CACHE_PATH" + bundle config --local jobs "$(nproc)" + bundle config --local without server docgen maintenance pry travis integration ci chefstyle + bundle config --local shebang "$(pkg_path_for "$_chef_client_ruby")/bin/ruby" + bundle config --local retry 5 + bundle config --local silence_root_warning 1 + ) + + build_line "Setting link for /usr/bin/env to 'coreutils'" + if [ ! -f /usr/bin/env ]; then + ln -s "$(pkg_interpreter_for core/coreutils bin/env)" /usr/bin/env + fi +} + +do_build() { + ( cd "$CACHE_PATH" || exit_with "unable to enter hab-cache directory" 1 + build_line "Installing gem dependencies ..." + bundle install --jobs=3 --retry=3 + build_line "Installing gems from git repos properly ..." + build_line "Installing this project's gems ..." + bundle exec rake install:local + gem install chef-utils chef-config appbundler + ) +} + +do_install() { + ( cd "$pkg_prefix" || exit_with "unable to enter pkg prefix directory" 1 + export BUNDLE_GEMFILE="${CACHE_PATH}/Gemfile" + build_line "** fixing binstub shebangs" + fix_interpreter "${pkg_prefix}/vendor/bin/*" "$_chef_client_ruby" bin/ruby + export BUNDLE_GEMFILE="${CACHE_PATH}/Gemfile" + for gem in chef-cli; do + build_line "** generating binstubs for $gem with precise version pins" + appbundler $CACHE_PATH $pkg_prefix/bin $gem + done + ) +} + +do_after() { + build_line "Trimming the fat ..." + + # We don't need the cache of downloaded .gem files ... + rm -rf "$pkg_prefix/vendor/cache" + + # We don't need the gem docs. + rm -rf "$pkg_prefix/vendor/doc" + # We don't need to ship the test suites for every gem dependency, + # only Chef's for package verification. + find "$pkg_prefix/vendor/gems" -name spec -type d | grep -v "chef-cli-${pkg_version}" \ + | while read spec_dir; do rm -rf "$spec_dir"; done +} + +do_end() { + if [ "$(readlink /usr/bin/env)" = "$(pkg_interpreter_for core/coreutils bin/env)" ]; then + build_line "Removing the symlink we created for '/usr/bin/env'" + rm /usr/bin/env + fi +} + +do_strip() { + return 0 +} \ No newline at end of file diff --git a/lib/chef-cli/command/env.rb b/lib/chef-cli/command/env.rb index d1aed4b2..c44e4c4e 100644 --- a/lib/chef-cli/command/env.rb +++ b/lib/chef-cli/command/env.rb @@ -73,19 +73,19 @@ def ruby_info def gem_environment h = {} - h["GEM ROOT"] = omnibus_env["GEM_ROOT"] - h["GEM HOME"] = omnibus_env["GEM_HOME"] - h["GEM PATHS"] = omnibus_env["GEM_PATH"].split(File::PATH_SEPARATOR) - rescue OmnibusInstallNotFound + # h["GEM ROOT"] = omnibus_env["GEM_ROOT"] + # h["GEM HOME"] = omnibus_env["GEM_HOME"] + # h["GEM PATHS"] = omnibus_env["GEM_PATH"].split(File::PATH_SEPARATOR) + # rescue OmnibusInstallNotFound h["GEM_ROOT"] = ENV["GEM_ROOT"] if ENV.key?("GEM_ROOT") h["GEM_HOME"] = ENV["GEM_HOME"] if ENV.key?("GEM_HOME") h["GEM PATHS"] = ENV["GEM_PATH"].split(File::PATH_SEPARATOR) if ENV.key?("GEM_PATH") && !ENV.key?("GEM_PATH").nil? - ensure - h + # ensure + # h end def paths - omnibus_env["PATH"].split(File::PATH_SEPARATOR) + habitat_env["PATH"].split(File::PATH_SEPARATOR) rescue OmnibusInstallNotFound ENV["PATH"].split(File::PATH_SEPARATOR) end diff --git a/lib/chef-cli/command/exec.rb b/lib/chef-cli/command/exec.rb index f1e19bde..9b86bbea 100644 --- a/lib/chef-cli/command/exec.rb +++ b/lib/chef-cli/command/exec.rb @@ -30,7 +30,7 @@ class Exec < ChefCLI::Command::Base def run(params) # Set ENV directly on the "parent" process (us) before running #exec to # ensure the custom PATH is honored when finding the command to exec - omnibus_env.each { |var, value| ENV[var] = value } + habitat_env.each { |var, value| ENV[var] = value } exec(*params) raise "Exec failed without an exception, your ruby is buggy" # should never get here end diff --git a/lib/chef-cli/helpers.rb b/lib/chef-cli/helpers.rb index 6c72237e..7c6e21ad 100644 --- a/lib/chef-cli/helpers.rb +++ b/lib/chef-cli/helpers.rb @@ -53,24 +53,24 @@ def stderr # # Locates the omnibus directories # - def omnibus_install? - # We also check if the location we're running from (omnibus_root is relative to currently-running ruby) - # includes the version manifest that omnibus packages ship with. If it doesn't, then we're running locally - # or out of a gem - so not as an 'omnibus install' - File.exist?(expected_omnibus_root) && File.exist?(File.join(expected_omnibus_root, "version-manifest.json")) - end + # def omnibus_install? + # # We also check if the location we're running from (omnibus_root is relative to currently-running ruby) + # # includes the version manifest that omnibus packages ship with. If it doesn't, then we're running locally + # # or out of a gem - so not as an 'omnibus install' + # File.exist?(expected_omnibus_root) && File.exist?(File.join(expected_omnibus_root, "version-manifest.json")) + # end - def omnibus_root - @omnibus_root ||= omnibus_expand_path(expected_omnibus_root) - end + # def omnibus_root + # @omnibus_root ||= omnibus_expand_path(expected_omnibus_root) + # end - def omnibus_bin_dir - @omnibus_bin_dir ||= omnibus_expand_path(omnibus_root, "bin") - end + # def omnibus_bin_dir + # @omnibus_bin_dir ||= omnibus_expand_path(omnibus_root, "bin") + # end - def omnibus_embedded_bin_dir - @omnibus_embedded_bin_dir ||= omnibus_expand_path(omnibus_root, "embedded", "bin") - end + # def omnibus_embedded_bin_dir + # @omnibus_embedded_bin_dir ||= omnibus_expand_path(omnibus_root, "embedded", "bin") + # end def package_home @package_home ||= begin @@ -110,37 +110,56 @@ def git_windows_bin_dir @git_windows_bin_dir ||= File.expand_path(File.join(omnibus_root, "embedded", "git", "usr", "bin")) end + def initialize + @pkg_prefix = get_pkg_prefix + end + # - # environment vars for omnibus + # environment vars for habitat # - def omnibus_env - @omnibus_env ||= - begin - user_bin_dir = File.expand_path(File.join(Gem.user_dir, "bin")) - path = [ omnibus_bin_dir, user_bin_dir, omnibus_embedded_bin_dir, ENV["PATH"].split(File::PATH_SEPARATOR) ] - path << git_bin_dir if Dir.exist?(git_bin_dir) - path << git_windows_bin_dir if Dir.exist?(git_windows_bin_dir) - { - "PATH" => path.flatten.uniq.join(File::PATH_SEPARATOR), - "GEM_ROOT" => Gem.default_dir, - "GEM_HOME" => Gem.user_dir, - "GEM_PATH" => Gem.path.join(File::PATH_SEPARATOR), - } - end + def habitat_env + @habitat_env ||= + begin + # Define the necessary paths for the Habitat environment + # Custom GEM_HOME within Habitat + vendor_dir = File.join(@pkg_prefix, "vendor") + path = [ + File.join(@pkg_prefix, "bin"), + ENV["PATH"].split(File::PATH_SEPARATOR) # Preserve existing PATH + ].flatten.uniq + + { + "PATH" => path.join(File::PATH_SEPARATOR), + "GEM_ROOT" => Gem.default_dir, # Default directory for gems + "GEM_HOME" => vendor_dir, # GEM_HOME pointing to the vendor directory + "GEM_PATH" => vendor_dir, # GEM_PATH also pointing to the vendor directory + } + end end - def omnibus_expand_path(*paths) - dir = File.expand_path(File.join(paths)) - raise OmnibusInstallNotFound.new unless dir && File.directory?(dir) + def get_pkg_prefix + pkg_name = "ngupta26/chef-cli" # Your origin and package name + path = `hab pkg path #{pkg_name}`.strip - dir + if $?.success? && !path.empty? + path + else + raise "Failed to get pkg_prefix for #{pkg_name}: #{path}" + end end + # def omnibus_expand_path(*paths) + # dir = File.expand_path(File.join(paths)) + # raise OmnibusInstallNotFound.new unless dir && File.directory?(dir) + + # dir + # end + private - def expected_omnibus_root - File.expand_path(File.join(Gem.ruby, "..", "..", "..")) - end + # def expected_omnibus_root + # File.expand_path(File.join(Gem.ruby, "..", "..", "..")) + # end def default_package_home if Chef::Platform.windows?