lib/appbundler/app.rb in appbundler-0.11.6 vs lib/appbundler/app.rb in appbundler-0.12.0

- old
+ new

@@ -16,16 +16,34 @@ attr_reader :bundle_path attr_reader :target_bin_dir attr_reader :name + # The bundle_path is always the path to the Gemfile.lock being used, e.g. + # /var/cache/omnibus/src/chef/chef-14.10.9/Gemfile.lock or whatever. If + # the name if the gem is not set then we behave like old style 2-arg appbundling + # where the gem we are appbundling is in the gemspec in that directory. + # + # If the name is not nil, then we are doing a multiple-app appbundle where + # the Gemfile.lock is the omnibus Gemfile.lock and multiple app gems may be + # appbundled against the same Gemfile.lock. + # + # @param bundle_path [String] the directory path of the Gemfile.lock + # @param target_bin_dir [String] the binstub dir, e.g. /opt/chefdk/bin + # @param name [String] name of the gem def initialize(bundle_path, target_bin_dir, name) @bundle_path = bundle_path @target_bin_dir = target_bin_dir @name = name end + # For the 2-arg version this is the gemfile in the omnibus build directory: + # /var/cache/omnibus/src/chef/chef-14.10.9/Gemfile + # + # For the 3-arg version this is the gemfile in the gems installed directory: + # /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/berkshelf-7.0.7/Gemfile + # def gemfile_path "#{app_dir}/Gemfile" end def safe_resolve_local_gem(s) @@ -36,10 +54,26 @@ def requirement_to_str(req) req.as_list.map { |r| "\"#{r}\"" }.join(", ") end + # This is only used in the 3-arg version. The gemfile_path is the path into the actual + # installed gem, e.g.: /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/berkshelf-7.0.7/Gemfile + # + # The gemfile_lock is the omnibus gemfile.lock which is in this case: + # /var/cache/omnibus/src/chef-dk/chef-dk-3.8.14/Gemfile.lock + # + # This solves the app gems dependencies against the Gemfile.locks pins so that they do not + # conflict (assuming such a solution can be found). + # + # The "without" argument here applies to the app's Gemfile. There is no information in + # a rendered Gemfile.lock about gem groupings (literally none of that information is ever + # rendered by bundler into a Gemfile.lock -- open one up and look for yourself). So this + # without argument then applies only to the transitive gemfile locking creation. This + # codepath does not affect what gems we ship, and does not affect the generation of the + # binstubs. + # def requested_dependencies(without) Bundler.settings.temporary(without: without) do definition = Bundler::Definition.build(gemfile_path, gemfile_lock, nil) definition.send(:requested_dependencies) end @@ -50,14 +84,31 @@ # of our appbundle calls. But to ship ChefDK 2.0 we just do this. SHITLIST = [ "github_changelog_generator", ] + # This is a check which is equivalent to asking if we are running 2-arg or 3-arg. If + # we have an "external_lockfile" that means the chef-dk omnibus Gemfile.lock, e.g.: + # /var/cache/omnibus/src/chef-dk/chef-dk-3.8.14/Gemfile.lock is being merged with the + # Gemfile in e.g. /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/berkshelf-7.0.7/Gemfile. + # Hence the lockfile is "external" to the gem (it made sense to me at the time). + # + # If it is not then we're dealing with a single gem install from a single project and not + # doing any of the transitive locking and we generate a single set of binstubs from a single + # app in a single Gemfile.lock + # def external_lockfile? app_dir != bundle_path end + # This loads the specs from the Gemfile.lock which is called on the command line and is in + # the omnibus build space. + # + # Somewhat confusingly this is also the same as the "external" gemfile.lock, which was originally + # called the "local" gemfile.lock here. In either case it is something like: + # /var/cache/omnibus/src/chef-dk/chef-dk-3.8.14/Gemfile.lock + # def local_gemfile_lock_specs gemfile_lock_specs.map do |s| #if SHITLIST.include?(s.name) # nil #else @@ -66,10 +117,14 @@ end.compact end # Copy over any .bundler and Gemfile.lock files to the target gem # directory. This will let us run tests from under that directory. + # + # This is only on the 2-arg implementations pathway. This is not used + # for the 3-arg version. + # def copy_bundler_env gem_path = installed_spec.gem_dir # If we're already using that directory, don't copy (it won't work anyway) return if gem_path == File.dirname(gemfile_lock) FileUtils.install(gemfile_lock, gem_path, :mode => 0644) @@ -77,10 +132,16 @@ FileUtils.cp_r(dot_bundle_dir, gem_path) FileUtils.chmod_R("ugo+rX", File.join(gem_path, ".bundle")) end end + # This is the implementation of the 3-arg version of writing the merged lockfiles, + # when called with the 2-arg version it short-circuits, however, to the copy_bundler_env + # version above. + # + # This code does not affect the generated binstubs at all. + # def write_merged_lockfiles(without: []) unless external_lockfile? copy_bundler_env return end @@ -294,17 +355,29 @@ def installed_spec Gem::Specification.find_by_name(app_spec.name, app_spec.version) end + # In the 2-arg version of appbundler this loads the gemspec from the omnibus source + # build directory (e.g. /var/cache/omnibus/src/chef/chef-14.10.9/chef.gemspec) + # + # For the 3-arg version of appbundler this loads the gemspec from the installed path + # of the gem (e.g. /opt/chefdk/embedded/lib/ruby/gems/2.5.0/specifications/berkshelf-7.0.7.gemspec) + # def app_spec if name.nil? Gem::Specification.load("#{bundle_path}/#{File.basename(@bundle_path)}.gemspec") else spec_for(name) end end + # In the 2-arg version of appbundler this will be the the appdir of the gemspec in the + # omnibus build directory (e.g. /var/cache/omnibus/src/chef/chef-14.10.9) + # + # In the 3-arg version of appbundler this will be the installed gems path + # (e.g. /opt/chefdk/embedded/lib/ruby/gems/2.5.0/gems/berkshelf-7.0.7/) + # def app_dir if name.nil? File.dirname(app_spec.loaded_from) else installed_spec.gem_dir