# frozen_string_literal: true require "bundler/shared_helpers" require "shellwords" module Spec module Builders def self.constantize(name) name.delete("-").upcase end def v(version) Gem::Version.new(version) end def pl(platform) Gem::Platform.new(platform) end # Returns a number smaller than the size of the index. Useful for specs that # need the API request limit to be reached for some reason. def low_api_request_limit_for(gem_repo) all_gems = Dir[gem_repo.join("gems/*.gem")] all_gem_names = all_gems.map do |file| File.basename(file, ".gem").match(/\A(?[^-]+)-.*\z/)[:gem_name] end.uniq (all_gem_names - ["bundler"]).size end def build_repo1 rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first build_repo gem_repo1 do FileUtils.cp rake_path, "#{gem_repo1}/gems/" build_gem "rack", %w[0.9.1 1.0.0] do |s| s.executables = "rackup" s.post_install_message = "Rack's post install message" end build_gem "thin" do |s| s.add_dependency "rack" s.post_install_message = "Thin's post install message" end build_gem "rack-obama" do |s| s.add_dependency "rack" s.post_install_message = "Rack-obama's post install message" end build_gem "rack_middleware", "1.0" do |s| s.add_dependency "rack", "0.9.1" end build_gem "rails", "2.3.2" do |s| s.executables = "rails" s.add_dependency "rake", "13.0.1" s.add_dependency "actionpack", "2.3.2" s.add_dependency "activerecord", "2.3.2" s.add_dependency "actionmailer", "2.3.2" s.add_dependency "activeresource", "2.3.2" end build_gem "actionpack", "2.3.2" do |s| s.add_dependency "activesupport", "2.3.2" end build_gem "activerecord", ["2.3.1", "2.3.2"] do |s| s.add_dependency "activesupport", "2.3.2" end build_gem "actionmailer", "2.3.2" do |s| s.add_dependency "activesupport", "2.3.2" end build_gem "activeresource", "2.3.2" do |s| s.add_dependency "activesupport", "2.3.2" end build_gem "activesupport", %w[1.2.3 2.3.2 2.3.5] build_gem "activemerchant" do |s| s.add_dependency "activesupport", ">= 2.0.0" end build_gem "rspec", "1.2.7", :no_default => true do |s| s.write "lib/spec.rb", "SPEC = '1.2.7'" end build_gem "rack-test", :no_default => true do |s| s.write "lib/rack/test.rb", "RACK_TEST = '1.0'" end build_gem "platform_specific" do |s| s.platform = Bundler.local_platform s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'" end build_gem "platform_specific" do |s| s.platform = "java" s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 JAVA'" end build_gem "platform_specific" do |s| s.platform = "ruby" s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'" end build_gem "platform_specific" do |s| s.platform = "x86-mswin32" s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 MSWIN'" end build_gem "platform_specific" do |s| s.platform = "x86-mingw32" end build_gem "platform_specific" do |s| s.platform = "x64-mingw32" end build_gem "platform_specific" do |s| s.platform = "x86-darwin-100" s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 x86-darwin-100'" end build_gem "only_java", "1.0" do |s| s.platform = "java" s.write "lib/only_java.rb", "ONLY_JAVA = '1.0.0 JAVA'" end build_gem "only_java", "1.1" do |s| s.platform = "java" s.write "lib/only_java.rb", "ONLY_JAVA = '1.1.0 JAVA'" end build_gem "nokogiri", "1.4.2" build_gem "nokogiri", "1.4.2" do |s| s.platform = "java" s.write "lib/nokogiri.rb", "NOKOGIRI = '1.4.2 JAVA'" s.add_dependency "weakling", ">= 0.0.3" end build_gem "laduradura", "5.15.2" build_gem "laduradura", "5.15.2" do |s| s.platform = "java" s.write "lib/laduradura.rb", "LADURADURA = '5.15.2 JAVA'" end build_gem "laduradura", "5.15.3" do |s| s.platform = "java" s.write "lib/laduradura.rb", "LADURADURA = '5.15.2 JAVA'" end build_gem "weakling", "0.0.3" build_gem "terranova", "8" build_gem "duradura", "7.0" build_gem "very_simple_binary", &:add_c_extension build_gem "simple_binary", &:add_c_extension build_gem "bundler", "0.9" do |s| s.executables = "bundle" s.write "bin/bundle", "puts 'FAIL'" end # The bundler 0.8 gem has a rubygems plugin that always loads :( build_gem "bundler", "0.8.1" do |s| s.write "lib/bundler/omg.rb", "" s.write "lib/rubygems_plugin.rb", "require 'bundler/omg' ; puts 'FAIL'" end # The yard gem iterates over Gem.source_index looking for plugins build_gem "yard" do |s| s.write "lib/yard.rb", <<-Y Gem::Specification.sort_by(&:name).each do |gem| puts gem.full_name end Y end build_gem "net-ssh" build_gem "net-sftp", "1.1.1" do |s| s.add_dependency "net-ssh", ">= 1.0.0", "< 1.99.0" end build_gem "foo" end end def build_repo2(&blk) FileUtils.rm_rf gem_repo2 FileUtils.cp_r gem_repo1, gem_repo2 update_repo2(&blk) if block_given? end # A repo that has no pre-installed gems included. (The caller completely # determines the contents with the block.) def build_repo4(&blk) FileUtils.rm_rf gem_repo4 build_repo(gem_repo4, &blk) end def update_repo4(&blk) update_repo(gem_repo4, &blk) end def update_repo2 update_repo gem_repo2 do yield if block_given? end end def build_security_repo build_repo security_repo do build_gem "rack" build_gem "signed_gem" do |s| cert = "signing-cert.pem" pkey = "signing-pkey.pem" s.write cert, TEST_CERT s.write pkey, TEST_PKEY s.signing_key = pkey s.cert_chain = [cert] end end end def build_repo(path, &blk) return if File.directory?(path) FileUtils.mkdir_p("#{path}/gems") update_repo(path, &blk) end def check_test_gems! rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first if rake_path.nil? FileUtils.rm_rf(Path.base_system_gems) Spec::Rubygems.install_test_deps rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first end if rake_path.nil? abort "Your test gems are missing! Run `rm -rf #{tmp}` and try again." end end def update_repo(path) if path == gem_repo1 && caller.first.split(" ").last == "`build_repo`" raise "Updating gem_repo1 is unsupported -- use gem_repo2 instead" end return unless block_given? @_build_path = "#{path}/gems" @_build_repo = File.basename(path) yield with_gem_path_as Path.base_system_gems do gem_command :generate_index, :dir => path end ensure @_build_path = nil @_build_repo = nil end def build_index(&block) index = Bundler::Index.new IndexBuilder.run(index, &block) if block_given? index end def build_spec(name, version = "0.0.1", platform = nil, &block) Array(version).map do |v| Gem::Specification.new do |s| s.name = name s.version = Gem::Version.new(v) s.platform = platform s.authors = ["no one in particular"] s.summary = "a gemspec used only for testing" DepBuilder.run(s, &block) if block_given? end end end def build_dep(name, requirements = Gem::Requirement.default, type = :runtime) Bundler::Dependency.new(name, :version => requirements) end def build_lib(name, *args, &blk) build_with(LibBuilder, name, args, &blk) end def build_gem(name, *args, &blk) build_with(GemBuilder, name, args, &blk) end def build_git(name, *args, &block) opts = args.last.is_a?(Hash) ? args.last : {} builder = opts[:bare] ? GitBareBuilder : GitBuilder spec = build_with(builder, name, args, &block) GitReader.new(self, opts[:path] || lib_path(spec.full_name)) end def update_git(name, *args, &block) opts = args.last.is_a?(Hash) ? args.last : {} spec = build_with(GitUpdater, name, args, &block) GitReader.new(self, opts[:path] || lib_path(spec.full_name)) end def build_plugin(name, *args, &blk) build_with(PluginBuilder, name, args, &blk) end private def build_with(builder, name, args, &blk) @_build_path ||= nil @_build_repo ||= nil options = args.last.is_a?(Hash) ? args.pop : {} versions = args.last || "1.0" spec = nil options[:path] ||= @_build_path options[:source] ||= @_build_repo Array(versions).each do |version| spec = builder.new(self, name, version) yield spec if block_given? spec._build(options) end spec end class IndexBuilder include Builders def self.run(index, &block) new(index).run(&block) end def initialize(index) @index = index end def run(&block) instance_eval(&block) end def gem(*args, &block) build_spec(*args, &block).each do |s| @index << s end end def platforms(platforms) platforms.split(/\s+/).each do |platform| platform.gsub!(/^(mswin32)$/, 'x86-\1') yield Gem::Platform.new(platform) end end def versions(versions) versions.split(/\s+/).each {|version| yield v(version) } end end class DepBuilder include Builders def self.run(spec, &block) new(spec).run(&block) end def initialize(spec) @spec = spec end def run(&block) instance_eval(&block) end def runtime(name, requirements) @spec.add_runtime_dependency(name, requirements) end def development(name, requirements) @spec.add_development_dependency(name, requirements) end def required_ruby_version=(*reqs) @spec.required_ruby_version = *reqs end alias_method :dep, :runtime end class LibBuilder def initialize(context, name, version) @context = context @name = name @spec = Gem::Specification.new do |s| s.name = name s.version = version s.summary = "This is just a fake gem for testing" s.description = "This is a completely fake gem, for testing purposes." s.author = "no one" s.email = "foo@bar.baz" s.homepage = "http://example.com" s.license = "MIT" end @files = {} end def method_missing(*args, &blk) @spec.send(*args, &blk) end def write(file, source = "") @files[file] = source end def executables=(val) @spec.executables = Array(val) @spec.executables.each do |file| executable = "#{@spec.bindir}/#{file}" shebang = if Bundler.current_ruby.jruby? "#!/usr/bin/env jruby\n" else "#!/usr/bin/env ruby\n" end @spec.files << executable write executable, "#{shebang}require_relative '../lib/#{@name}' ; puts #{Builders.constantize(@name)}" end end def add_c_extension require_paths << "ext" extensions << "ext/extconf.rb" write "ext/extconf.rb", <<-RUBY require "mkmf" # exit 1 unless with_config("simple") extension_name = "#{name}_c" if extra_lib_dir = with_config("ext-lib") # add extra libpath if --with-ext-lib is # passed in as a build_arg dir_config extension_name, nil, extra_lib_dir else dir_config extension_name end create_makefile extension_name RUBY write "ext/#{name}.c", <<-C #include "ruby.h" void Init_#{name}_c() { rb_define_module("#{Builders.constantize(name)}_IN_C"); } C end def _build(options) path = options[:path] || _default_path if options[:rubygems_version] @spec.rubygems_version = options[:rubygems_version] def @spec.mark_version; end def @spec.validate(*); end end unless options[:no_default] gem_source = options[:source] || "path@#{path}" @files = _default_files. merge("lib/#{entrypoint}/source.rb" => "#{Builders.constantize(name)}_SOURCE = #{gem_source.to_s.dump}"). merge(@files) end @spec.authors = ["no one"] @spec.files = @files.keys case options[:gemspec] when false # do nothing when :yaml @spec.files << "#{name}.gemspec" @files["#{name}.gemspec"] = @spec.to_yaml else @spec.files << "#{name}.gemspec" @files["#{name}.gemspec"] = @spec.to_ruby end @files.each do |file, source| file = Pathname.new(path).join(file) FileUtils.mkdir_p(file.dirname) File.open(file, "w") {|f| f.puts source } File.chmod("+x", file) if @spec.executables.map {|exe| "#{@spec.bindir}/#{exe}" }.include?(file) end path end def _default_files @_default_files ||= { "lib/#{entrypoint}.rb" => "#{Builders.constantize(name)} = '#{version}#{platform_string}'" } end def entrypoint name.tr("-", "/") end def _default_path @context.tmp("libs", @spec.full_name) end def platform_string " #{@spec.platform}" unless @spec.platform == Gem::Platform::RUBY end end class GitBuilder < LibBuilder def _build(options) default_branch = options[:default_branch] || "master" path = options[:path] || _default_path source = options[:source] || "git@#{path}" super(options.merge(:path => path, :source => source)) @context.git("config --global init.defaultBranch #{default_branch}", path) @context.git("init", path) @context.git("add *", path) @context.git("config user.email lol@wut.com", path) @context.git("config user.name lolwut", path) @context.git("config commit.gpgsign false", path) @context.git("commit -m OMG_INITIAL_COMMIT", path) end end class GitBareBuilder < LibBuilder def _build(options) path = options[:path] || _default_path super(options.merge(:path => path)) @context.git("init --bare", path) end end class GitUpdater < LibBuilder def _build(options) libpath = options[:path] || _default_path update_gemspec = options[:gemspec] || false source = options[:source] || "git@#{libpath}" @context.git "checkout master", libpath if branch = options[:branch] raise "You can't specify `master` as the branch" if branch == "master" escaped_branch = Shellwords.shellescape(branch) if @context.git("branch -l #{escaped_branch}", libpath).empty? @context.git("branch #{escaped_branch}", libpath) end @context.git("checkout #{escaped_branch}", libpath) elsif tag = options[:tag] @context.git("tag #{Shellwords.shellescape(tag)}", libpath) elsif options[:remote] @context.git("remote add origin #{options[:remote]}", libpath) elsif options[:push] @context.git("push origin #{options[:push]}", libpath) end current_ref = @context.git("rev-parse HEAD", libpath).strip _default_files.keys.each do |path| _default_files[path] += "\n#{Builders.constantize(name)}_PREV_REF = '#{current_ref}'" end super(options.merge(:path => libpath, :gemspec => update_gemspec, :source => source)) @context.git("add *", libpath) @context.git("commit -m BUMP", libpath, :raise_on_error => false) end end class GitReader attr_reader :context, :path def initialize(context, path) @context = context @path = path end def ref_for(ref, len = nil) ref = context.git "rev-parse #{ref}", path ref = ref[0..len] if len ref end end class GemBuilder < LibBuilder def _build(opts) lib_path = super(opts.merge(:path => @context.tmp(".tmp/#{@spec.full_name}"), :no_default => opts[:no_default])) destination = opts[:path] || _default_path FileUtils.mkdir_p(lib_path.join(destination)) if opts[:gemspec] == :yaml || opts[:gemspec] == false Dir.chdir(lib_path) do Bundler.rubygems.build(@spec, opts[:skip_validation]) end elsif opts[:skip_validation] @context.gem_command "build --force #{@spec.name}", :dir => lib_path else @context.gem_command "build #{@spec.name}", :dir => lib_path end gem_path = File.expand_path("#{@spec.full_name}.gem", lib_path) if opts[:to_system] @context.system_gems gem_path, :default => opts[:default] elsif opts[:to_bundle] @context.system_gems gem_path, :path => @context.default_bundle_path else FileUtils.mv(gem_path, destination) end end def _default_path @context.gem_repo1("gems") end end class PluginBuilder < GemBuilder def _default_files @_default_files ||= { "lib/#{name}.rb" => "#{Builders.constantize(name)} = '#{version}#{platform_string}'", "plugins.rb" => "", } end end TEST_CERT = <<-CERT.gsub(/^\s*/, "") -----BEGIN CERTIFICATE----- MIIDMjCCAhqgAwIBAgIBATANBgkqhkiG9w0BAQUFADAnMQwwCgYDVQQDDAN5b3Ux FzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTE1MDIwODAwMTIyM1oXDTQyMDYy NTAwMTIyM1owJzEMMAoGA1UEAwwDeW91MRcwFQYKCZImiZPyLGQBGRYHZXhhbXBs ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANlvFdpN43c4DMS9Jo06 m0a7k3bQ3HWQ1yrYhZMi77F1F73NpBknYHIzDktQpGn6hs/4QFJT4m4zNEBF47UL jHU5nTK5rjkS3niGYUjvh3ZEzVeo9zHUlD/UwflDo4ALl3TSo2KY/KdPS/UTdLXL ajkQvaVJtEDgBPE3DPhlj5whp+Ik3mDHej7qpV6F502leAwYaFyOtlEG/ZGNG+nZ L0clH0j77HpP42AylHDi+vakEM3xcjo9BeWQ6Vkboic93c9RTt6CWBWxMQP7Nol1 MOebz9XOSQclxpxWteXNfPRtMdAhmRl76SMI8ywzThNPpa4EH/yz34ftebVOgKyM nd0CAwEAAaNpMGcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFA7D n9qo0np23qi3aOYuAAPn/5IdMBYGA1UdEQQPMA2BC3lvdUBleGFtcGxlMBYGA1Ud EgQPMA2BC3lvdUBleGFtcGxlMA0GCSqGSIb3DQEBBQUAA4IBAQA7Gyk62sWOUX/N vk4tJrgKESph6Ns8+E36A7n3jt8zCep8ldzMvwTWquf9iqhsC68FilEoaDnUlWw7 d6oNuaFkv7zfrWGLlvqQJC+cu2X5EpcCksg5oRp8VNbwJysJ6JgwosxzROII8eXc R+j1j6mDvQYqig2QOnzf480pjaqbP+tspfDFZbhKPrgM3Blrb3ZYuFpv4zkqI7aB 6fuk2DUhNO1CuwrJA84TqC+jGo73bDKaT5hrIDiaJRrN5+zcWja2uEWrj5jSbep4 oXdEdyH73hOHMBP40uds3PqnUsxEJhzjB2sCCe1geV24kw9J4m7EQXPVkUKDgKrt LlpDmOoo -----END CERTIFICATE----- CERT TEST_PKEY = <<-PKEY.gsub(/^\s*/, "") -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEA2W8V2k3jdzgMxL0mjTqbRruTdtDcdZDXKtiFkyLvsXUXvc2k GSdgcjMOS1CkafqGz/hAUlPibjM0QEXjtQuMdTmdMrmuORLeeIZhSO+HdkTNV6j3 MdSUP9TB+UOjgAuXdNKjYpj8p09L9RN0tctqORC9pUm0QOAE8TcM+GWPnCGn4iTe YMd6PuqlXoXnTaV4DBhoXI62UQb9kY0b6dkvRyUfSPvsek/jYDKUcOL69qQQzfFy Oj0F5ZDpWRuiJz3dz1FO3oJYFbExA/s2iXUw55vP1c5JByXGnFa15c189G0x0CGZ GXvpIwjzLDNOE0+lrgQf/LPfh+15tU6ArIyd3QIDAQABAoIBACbDqz20TS1gDMa2 gj0DidNedbflHKjJHdNBru7Ad8NHgOgR1YO2hXdWquG6itVqGMbTF4SV9/R1pIcg 7qvEV1I+50u31tvOBWOvcYCzU48+TO2n7gowQA3xPHPYHzog1uu48fAOHl0lwgD7 av9OOK3b0jO5pC08wyTOD73pPWU0NrkTh2+N364leIi1pNuI1z4V+nEuIIm7XpVd 5V4sXidMTiEMJwE6baEDfTjHKaoRndXrrPo3ryIXmcX7Ag1SwAQwF5fBCRToCgIx dszEZB1bJD5gA6r+eGnJLB/F60nK607az5o3EdguoB2LKa6q6krpaRCmZU5svvoF J7xgBPECgYEA8RIzHAQ3zbaibKdnllBLIgsqGdSzebTLKheFuigRotEV3Or/z5Lg k/nVnThWVkTOSRqXTNpJAME6a4KTdcVSxYP+SdZVO1esazHrGb7xPVb7MWSE1cqp WEk3Yy8OUOPoPQMc4dyGzd30Mi8IBB6gnFIYOTrpUo0XtkBv8rGGhfsCgYEA5uYn 6QgL4NqNT84IXylmMb5ia3iBt6lhxI/A28CDtQvfScl4eYK0IjBwdfG6E1vJgyzg nJzv3xEVo9bz+Kq7CcThWpK5JQaPnsV0Q74Wjk0ShHet15txOdJuKImnh5F6lylC GTLR9gnptytfMH/uuw4ws0Q2kcg4l5NHKOWOnAcCgYEAvAwIVkhsB0n59Wu4gCZu FUZENxYWUk/XUyQ6KnZrG2ih90xQ8+iMyqFOIm/52R2fFKNrdoWoALC6E3ct8+ZS pMRLrelFXx8K3it4SwMJR2H8XBEfFW4bH0UtsW7Zafv+AunUs9LETP5gKG1LgXsq qgXX43yy2LQ61O365YPZfdUCgYBVbTvA3MhARbvYldrFEnUL3GtfZbNgdxuD9Mee xig0eJMBIrgfBLuOlqtVB70XYnM4xAbKCso4loKSHnofO1N99siFkRlM2JOUY2tz kMWZmmxKdFjuF0WZ5f/5oYxI/QsFGC+rUQEbbWl56mMKd5qkvEhKWudxoklF0yiV ufC8SwKBgDWb8iWqWN5a/kfvKoxFcDM74UHk/SeKMGAL+ujKLf58F+CbweM5pX9C EUsxeoUEraVWTiyFVNqD81rCdceus9TdBj0ZIK1vUttaRZyrMAwF0uQSfjtxsOpd l69BkyvzjgDPkmOHVGiSZDLi3YDvypbUpo6LOy4v5rVg5U2F/A0v -----END RSA PRIVATE KEY----- PKEY end end