lib/appbundler/app.rb in appbundler-0.10.0 vs lib/appbundler/app.rb in appbundler-0.11.0

- old
+ new

@@ -1,7 +1,9 @@ require "bundler" require "fileutils" +require "mixlib/shellout" +require "tempfile" require "pp" module Appbundler class AppbundlerError < StandardError; end @@ -20,23 +22,118 @@ @bundle_path = bundle_path @target_bin_dir = target_bin_dir @name = name end - # Copy over any .bundler and Gemfile.lock files to the target gem - # directory. This will let us run tests from under that directory. - def copy_bundler_env - gem_path = app_gemspec.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) - if File.exist?(dot_bundle_dir) && File.directory?(dot_bundle_dir) - FileUtils.cp_r(dot_bundle_dir, gem_path) - FileUtils.chmod_R("ugo+rX", File.join(gem_path, ".bundle")) + def gemfile_path + "#{app_dir}/Gemfile" + end + + def safe_resolve_local_gem(s) + Gem::Specification.find_by_name(s.name, s.version) + rescue Gem::MissingSpecError + nil + end + + def requirement_to_str(req) + req.as_list.map { |r| "\"#{r}\"" }.join(", ") + end + + def requested_dependencies(without) + Bundler.settings.temporary(without: without) do + definition = Bundler::Definition.build(gemfile_path, gemfile_lock, nil) + definition.send(:requested_dependencies) end end + # This is a blatant ChefDK 2.0 hack. We need to audit all of our Gemfiles, make sure + # that github_changelog_generator is in its own group and exclude that group from all + # of our appbundle calls. But to ship ChefDK 2.0 we just do this. + SHITLIST = [ + "github_changelog_generator", + ] + + def external_lockfile? + app_dir != File.dirname(gemfile_lock) + end + + def local_gemfile_lock_specs + gemfile_lock_specs.map do |s| + #if SHITLIST.include?(s.name) + # nil + #else + safe_resolve_local_gem(s) + #end + end.compact + end + + def write_merged_lockfiles(without: []) + # just return we don't have an external lockfile + return unless external_lockfile? + + # handle external lockfile + Tempfile.open(".appbundler-gemfile", app_dir) do |t| + t.puts "source 'https://rubygems.org'" + + locked_gems = {} + + gemfile_lock_specs.each do |s| + #next if SHITLIST.include?(s.name) + spec = safe_resolve_local_gem(s) + next if spec.nil? + + case s.source + when Bundler::Source::Path + locked_gems[spec.name] = %Q{gem "#{spec.name}", path: "#{spec.gem_dir}"} + when Bundler::Source::Rubygems + # FIXME: should add the spec.version as a gem requirement below + locked_gems[spec.name] = %Q{gem "#{spec.name}", "= #{spec.version}"} + when Bundler::Source::Git + raise "FIXME: appbundler needs a patch to support Git gems" + else + raise "appbundler doens't know this source type" + end + end + + seen_gems = {} + + t.puts "# GEMS FROM GEMFILE:" + + requested_dependencies(without).each do |dep| + next if SHITLIST.include?(dep.name) + if locked_gems[dep.name] + t.puts locked_gems[dep.name] + else + string = %Q{gem "#{dep.name}", #{requirement_to_str(dep.requirement)}} + string << %Q{, platform: #{dep.platforms}} unless dep.platforms.empty? + t.puts string + end + seen_gems[dep.name] = true + end + + t.puts "# GEMS FROM LOCKFILE: " + + locked_gems.each do |name, line| + next if SHITLIST.include?(name) + next if seen_gems[name] + t.puts line + end + + t.close + puts IO.read(t.path) # debugging + Dir.chdir(app_dir) do + FileUtils.rm_f "#{app_dir}/Gemfile.lock" + Bundler.with_clean_env do + so = Mixlib::ShellOut.new("bundle lock", env: { "BUNDLE_GEMFILE" => t.path }) + so.run_command + so.error! + end + end + end + return "#{app_dir}/Gemfile.lock" + end + def write_executable_stubs executables_to_create = executables.map do |real_executable_path| basename = File.basename(real_executable_path) stub_path = File.join(target_bin_dir, basename) [real_executable_path, stub_path] @@ -150,11 +247,15 @@ spec = app_gemspec spec.executables.map { |e| spec.bin_file(e) } end def runtime_dep_specs - add_dependencies_from(app_spec) + if external_lockfile? + local_gemfile_lock_specs + else + add_dependencies_from(app_spec) + end end def app_dependency_names @app_dependency_names ||= app_spec.dependencies.map(&:name) end @@ -163,9 +264,13 @@ Gem::Specification.find_by_name(app_spec.name, app_spec.version) end def app_spec spec_for(name) + end + + def app_dir + app_gemspec.gem_dir end def gemfile_lock_specs parsed_gemfile_lock.specs end