summaryrefslogtreecommitdiff
path: root/lib/rubygems/builder.rb
blob: 2bcd4b0bb309b78a59bebc1fc01f9b7d3535680d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++

require 'rubygems/user_interaction'

##
# The Builder class processes RubyGem specification files
# to produce a .gem file.

class Gem::Builder

  include Gem::UserInteraction

  ##
  # Constructs a builder instance for the provided specification
  #
  # spec:: [Gem::Specification] The specification instance

  def initialize(spec)
    require "yaml"
    require "rubygems/package"
    require "rubygems/security"

    @spec = spec
  end

  ##
  # Builds the gem from the specification.  Returns the name of the file
  # written.

  def build
    @spec.mark_version
    @spec.validate
    @signer = sign
    write_package
    say success if Gem.configuration.verbose
    @spec.file_name
  end

  def success
    <<-EOM
  Successfully built RubyGem
  Name: #{@spec.name}
  Version: #{@spec.version}
  File: #{@spec.file_name}
EOM
  end

  private

  ##
  # If the signing key was specified, then load the file, and swap to the
  # public key (TODO: we should probably just omit the signing key in favor of
  # the signing certificate, but that's for the future, also the signature
  # algorithm should be configurable)

  def sign
    signer = nil

    if @spec.respond_to?(:signing_key) and @spec.signing_key then
      signer = Gem::Security::Signer.new @spec.signing_key, @spec.cert_chain
      @spec.signing_key = nil
      @spec.cert_chain = signer.cert_chain.map { |cert| cert.to_s }
    end

    signer
  end

  def write_package
    open @spec.file_name, 'wb' do |gem_io|
      Gem::Package.open gem_io, 'w', @signer do |pkg|
        pkg.metadata = @spec.to_yaml

        @spec.files.each do |file|
          next if File.directory? file
          next if file == @spec.file_name # Don't add gem onto itself

          stat = File.stat file
          mode = stat.mode & 0777
          size = stat.size

          pkg.add_file_simple file, mode, size do |tar_io|
            tar_io.write open(file, "rb") { |f| f.read }
          end
        end
      end
    end
  end

end