summaryrefslogtreecommitdiff
path: root/lib/rubygems/package
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-11-29 06:52:18 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-11-29 06:52:18 +0000
commit9694bb8cac12969300692dac5a1cf7aa4e3a46cd (patch)
treec3cb423d701f7049ba9382de052e2a937cd1302d /lib/rubygems/package
parent3f606b7063fc7a8b191556365ad343a314719a8d (diff)
* lib/rubygems*: Updated to RubyGems 2.0
* test/rubygems*: ditto. * common.mk (prelude): Updated for RubyGems 2.0 source rearrangement. * tool/change_maker.rb: Allow invalid UTF-8 characters in source files. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37976 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rubygems/package')
-rw-r--r--lib/rubygems/package/digest_io.rb64
-rw-r--r--lib/rubygems/package/f_sync_dir.rb23
-rw-r--r--lib/rubygems/package/old.rb147
-rw-r--r--lib/rubygems/package/tar_header.rb73
-rw-r--r--lib/rubygems/package/tar_input.rb235
-rw-r--r--lib/rubygems/package/tar_output.rb146
-rw-r--r--lib/rubygems/package/tar_reader.rb23
-rw-r--r--lib/rubygems/package/tar_writer.rb70
8 files changed, 312 insertions, 469 deletions
diff --git a/lib/rubygems/package/digest_io.rb b/lib/rubygems/package/digest_io.rb
new file mode 100644
index 0000000000..f8bde0f557
--- /dev/null
+++ b/lib/rubygems/package/digest_io.rb
@@ -0,0 +1,64 @@
+##
+# IO wrapper that creates digests of contents written to the IO it wraps.
+
+class Gem::Package::DigestIO
+
+ ##
+ # Collected digests for wrapped writes.
+ #
+ # {
+ # 'SHA1' => #<OpenSSL::Digest: [...]>,
+ # 'SHA512' => #<OpenSSL::Digest: [...]>,
+ # }
+
+ attr_reader :digests
+
+ ##
+ # Wraps +io+ and updates digest for each of the digest algorithms in
+ # the +digests+ Hash. Returns the digests hash. Example:
+ #
+ # io = StringIO.new
+ # digests = {
+ # 'SHA1' => OpenSSL::Digest.new('SHA1'),
+ # 'SHA512' => OpenSSL::Digest.new('SHA512'),
+ # }
+ #
+ # Gem::Package::DigestIO.wrap io, digests do |digest_io|
+ # digest_io.write "hello"
+ # end
+ #
+ # digests['SHA1'].hexdigest #=> "aaf4c61d[...]"
+ # digests['SHA512'].hexdigest #=> "9b71d224[...]"
+
+ def self.wrap io, digests
+ digest_io = new io, digests
+
+ yield digest_io
+
+ return digests
+ end
+
+ ##
+ # Creates a new DigestIO instance. Using ::wrap is recommended, see the
+ # ::wrap documentation for documentation of +io+ and +digests+.
+
+ def initialize io, digests
+ @io = io
+ @digests = digests
+ end
+
+ ##
+ # Writes +data+ to the underlying IO and updates the digests
+
+ def write data
+ result = @io.write data
+
+ @digests.each do |_, digest|
+ digest << data
+ end
+
+ result
+ end
+
+end
+
diff --git a/lib/rubygems/package/f_sync_dir.rb b/lib/rubygems/package/f_sync_dir.rb
deleted file mode 100644
index f7eb7f3ce3..0000000000
--- a/lib/rubygems/package/f_sync_dir.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- coding: utf-8 -*-
-#--
-# Copyright (C) 2004 Mauricio Julio Fernández Pradier
-# See LICENSE.txt for additional licensing information.
-#++
-
-module Gem::Package::FSyncDir
-
- private
-
- ##
- # make sure this hits the disc
-
- def fsync_dir(dirname)
- dir = open dirname, 'r'
- dir.fsync
- rescue # ignore IOError if it's an unpatched (old) Ruby
- ensure
- dir.close if dir rescue nil
- end
-
-end
-
diff --git a/lib/rubygems/package/old.rb b/lib/rubygems/package/old.rb
new file mode 100644
index 0000000000..552a5f3591
--- /dev/null
+++ b/lib/rubygems/package/old.rb
@@ -0,0 +1,147 @@
+#--
+# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
+# All rights reserved.
+# See LICENSE.txt for permissions.
+#++
+
+##
+# The format class knows the guts of the ancient .gem file format and provides
+# the capability to read such ancient gems.
+#
+# Please pretend this doesn't exist.
+
+class Gem::Package::Old < Gem::Package
+
+ undef_method :spec=
+
+ ##
+ # Creates a new old-format package reader for +gem+. Old-format packages
+ # cannot be written.
+
+ def initialize gem
+ require 'fileutils'
+ require 'zlib'
+ Gem.load_yaml
+
+ @gem = gem
+ @contents = nil
+ @spec = nil
+ end
+
+ ##
+ # A list of file names contained in this gem
+
+ def contents
+ return @contents if @contents
+
+ open @gem, 'rb' do |io|
+ read_until_dashes io # spec
+ header = file_list io
+
+ @contents = header.map { |file| file['path'] }
+ end
+ end
+
+ ##
+ # Extracts the files in this package into +destination_dir+
+
+ def extract_files destination_dir
+ errstr = "Error reading files from gem"
+
+ open @gem, 'rb' do |io|
+ read_until_dashes io # spec
+ header = file_list io
+ raise Gem::Exception, errstr unless header
+
+ header.each do |entry|
+ full_name = entry['path']
+
+ destination = install_location full_name, destination_dir
+
+ file_data = ''
+
+ read_until_dashes io do |line|
+ file_data << line
+ end
+
+ file_data = file_data.strip.unpack("m")[0]
+ file_data = Zlib::Inflate.inflate file_data
+
+ raise Gem::Package::FormatError, "#{full_name} in #{@gem} is corrupt" if
+ file_data.length != entry['size'].to_i
+
+ FileUtils.rm_rf destination
+
+ FileUtils.mkdir_p File.dirname destination
+
+ open destination, 'wb', entry['mode'] do |out|
+ out.write file_data
+ end
+
+ say destination if Gem.configuration.really_verbose
+ end
+ end
+ rescue Zlib::DataError
+ raise Gem::Exception, errstr
+ end
+
+ ##
+ # Reads the file list section from the old-format gem +io+
+
+ def file_list io # :nodoc:
+ header = ''
+
+ read_until_dashes io do |line|
+ header << line
+ end
+
+ YAML.load header
+ end
+
+ ##
+ # Reads lines until a "---" separator is found
+
+ def read_until_dashes io # :nodoc:
+ while (line = io.gets) && line.chomp.strip != "---" do
+ yield line if block_given?
+ end
+ end
+
+ ##
+ # Skips the Ruby self-install header in +io+.
+
+ def skip_ruby io # :nodoc:
+ loop do
+ line = io.gets
+
+ return if line.chomp == '__END__'
+ break unless line
+ end
+
+ raise Gem::Exception, "Failed to find end of ruby script while reading gem"
+ end
+
+ ##
+ # The specification for this gem
+
+ def spec
+ return @spec if @spec
+
+ yaml = ''
+
+ open @gem, 'rb' do |io|
+ skip_ruby io
+ read_until_dashes io do |line|
+ yaml << line
+ end
+ end
+
+ @spec = Gem::Specification.from_yaml yaml
+ rescue YAML::SyntaxError => e
+ raise Gem::Exception, "Failed to parse gem specification out of gem file"
+ rescue ArgumentError => e
+ raise Gem::Exception, "Failed to parse gem specification out of gem file"
+ end
+
+end
+
diff --git a/lib/rubygems/package/tar_header.rb b/lib/rubygems/package/tar_header.rb
index 4f923b9b5e..28da1db0b5 100644
--- a/lib/rubygems/package/tar_header.rb
+++ b/lib/rubygems/package/tar_header.rb
@@ -102,61 +102,24 @@ class Gem::Package::TarHeader
fields = header.unpack UNPACK_FORMAT
- name = fields.shift
- mode = fields.shift.oct
- uid = fields.shift.oct
- gid = fields.shift.oct
- size = fields.shift.oct
- mtime = fields.shift.oct
- checksum = fields.shift.oct
- typeflag = fields.shift
- linkname = fields.shift
- magic = fields.shift
- version = fields.shift.oct
- uname = fields.shift
- gname = fields.shift
- devmajor = fields.shift.oct
- devminor = fields.shift.oct
- prefix = fields.shift
-
- new :name => name,
- :mode => mode,
- :uid => uid,
- :gid => gid,
- :size => size,
- :mtime => mtime,
- :checksum => checksum,
- :typeflag => typeflag,
- :linkname => linkname,
- :magic => magic,
- :version => version,
- :uname => uname,
- :gname => gname,
- :devmajor => devmajor,
- :devminor => devminor,
- :prefix => prefix,
-
- :empty => empty
-
- # HACK unfactor for Rubinius
- #new :name => fields.shift,
- # :mode => fields.shift.oct,
- # :uid => fields.shift.oct,
- # :gid => fields.shift.oct,
- # :size => fields.shift.oct,
- # :mtime => fields.shift.oct,
- # :checksum => fields.shift.oct,
- # :typeflag => fields.shift,
- # :linkname => fields.shift,
- # :magic => fields.shift,
- # :version => fields.shift.oct,
- # :uname => fields.shift,
- # :gname => fields.shift,
- # :devmajor => fields.shift.oct,
- # :devminor => fields.shift.oct,
- # :prefix => fields.shift,
-
- # :empty => empty
+ new :name => fields.shift,
+ :mode => fields.shift.oct,
+ :uid => fields.shift.oct,
+ :gid => fields.shift.oct,
+ :size => fields.shift.oct,
+ :mtime => fields.shift.oct,
+ :checksum => fields.shift.oct,
+ :typeflag => fields.shift,
+ :linkname => fields.shift,
+ :magic => fields.shift,
+ :version => fields.shift.oct,
+ :uname => fields.shift,
+ :gname => fields.shift,
+ :devmajor => fields.shift.oct,
+ :devminor => fields.shift.oct,
+ :prefix => fields.shift,
+
+ :empty => empty
end
##
diff --git a/lib/rubygems/package/tar_input.rb b/lib/rubygems/package/tar_input.rb
deleted file mode 100644
index 77b4d698da..0000000000
--- a/lib/rubygems/package/tar_input.rb
+++ /dev/null
@@ -1,235 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-#++
-# Copyright (C) 2004 Mauricio Julio Fernández Pradier
-# See LICENSE.txt for additional licensing information.
-#--
-
-require 'zlib'
-Gem.load_yaml
-
-class Gem::Package::TarInput
-
- include Gem::Package::FSyncDir
- include Enumerable
-
- attr_reader :metadata
-
- private_class_method :new
-
- def self.open(io, security_policy = nil, &block)
- is = new io, security_policy
-
- yield is
- ensure
- is.close if is
- end
-
- def initialize(io, security_policy = nil)
- @io = io
- @tarreader = Gem::Package::TarReader.new @io
- has_meta = false
-
- data_sig, meta_sig, data_dgst, meta_dgst = nil, nil, nil, nil
- dgst_algo = security_policy ? Gem::Security::OPT[:dgst_algo] : nil
-
- @tarreader.each do |entry|
- case entry.full_name
- when "metadata"
- @metadata = load_gemspec entry.read
- has_meta = true
- when "metadata.gz"
- begin
- # if we have a security_policy, then pre-read the metadata file
- # and calculate it's digest
- sio = nil
- if security_policy
- Gem.ensure_ssl_available
- sio = StringIO.new(entry.read)
- meta_dgst = dgst_algo.digest(sio.string)
- sio.rewind
- end
-
- # Ruby 1.8 doesn't have encoding and YAML is UTF-8
- args = [sio || entry]
- args << { :external_encoding => Encoding::UTF_8 } if
- Object.const_defined?(:Encoding)
-
- gzis = Zlib::GzipReader.new(*args)
-
- # YAML wants an instance of IO
- @metadata = load_gemspec(gzis)
- has_meta = true
- ensure
- gzis.close unless gzis.nil?
- end
- when 'metadata.gz.sig'
- meta_sig = entry.read
- when 'data.tar.gz.sig'
- data_sig = entry.read
- when 'data.tar.gz'
- if security_policy
- Gem.ensure_ssl_available
- data_dgst = dgst_algo.digest(entry.read)
- end
- end
- end
-
- if security_policy then
- Gem.ensure_ssl_available
-
- # map trust policy from string to actual class (or a serialized YAML
- # file, if that exists)
- if String === security_policy then
- if Gem::Security::Policies.key? security_policy then
- # load one of the pre-defined security policies
- security_policy = Gem::Security::Policies[security_policy]
- elsif File.exist? security_policy then
- # FIXME: this doesn't work yet
- security_policy = YAML.load File.read(security_policy)
- else
- raise Gem::Exception, "Unknown trust policy '#{security_policy}'"
- end
- end
-
- if data_sig && data_dgst && meta_sig && meta_dgst then
- # the user has a trust policy, and we have a signed gem
- # file, so use the trust policy to verify the gem signature
-
- begin
- security_policy.verify_gem(data_sig, data_dgst, @metadata.cert_chain)
- rescue Exception => e
- raise "Couldn't verify data signature: #{e}"
- end
-
- begin
- security_policy.verify_gem(meta_sig, meta_dgst, @metadata.cert_chain)
- rescue Exception => e
- raise "Couldn't verify metadata signature: #{e}"
- end
- elsif security_policy.only_signed
- raise Gem::Exception, "Unsigned gem"
- else
- # FIXME: should display warning here (trust policy, but
- # either unsigned or badly signed gem file)
- end
- end
-
- @tarreader.rewind
-
- unless has_meta then
- path = io.path if io.respond_to? :path
- error = Gem::Package::FormatError.new 'no metadata found', path
- raise error
- end
- end
-
- def close
- @io.close
- @tarreader.close
- end
-
- def each(&block)
- @tarreader.each do |entry|
- next unless entry.full_name == "data.tar.gz"
- is = zipped_stream entry
-
- begin
- Gem::Package::TarReader.new is do |inner|
- inner.each(&block)
- end
- ensure
- is.close if is
- end
- end
-
- @tarreader.rewind
- end
-
- def extract_entry(destdir, entry, expected_md5sum = nil)
- if entry.directory? then
- dest = File.join destdir, entry.full_name
-
- if File.directory? dest then
- FileUtils.chmod entry.header.mode, dest, :verbose => false
- else
- FileUtils.mkdir_p dest, :mode => entry.header.mode, :verbose => false
- end
-
- fsync_dir dest
- fsync_dir File.join(dest, "..")
-
- return
- end
-
- # it's a file
- md5 = Digest::MD5.new if expected_md5sum
- destdir = File.join destdir, File.dirname(entry.full_name)
- FileUtils.mkdir_p destdir, :mode => 0755, :verbose => false
- destfile = File.join destdir, File.basename(entry.full_name)
- FileUtils.chmod 0600, destfile, :verbose => false rescue nil # Errno::ENOENT
-
- open destfile, "wb", entry.header.mode do |os|
- loop do
- data = entry.read 4096
- break unless data
- # HACK shouldn't we check the MD5 before writing to disk?
- md5 << data if expected_md5sum
- os.write(data)
- end
-
- os.fsync
- end
-
- FileUtils.chmod entry.header.mode, destfile, :verbose => false
- fsync_dir File.dirname(destfile)
- fsync_dir File.join(File.dirname(destfile), "..")
-
- if expected_md5sum && expected_md5sum != md5.hexdigest then
- raise Gem::Package::BadCheckSum
- end
- end
-
- # Attempt to YAML-load a gemspec from the given _io_ parameter. Return
- # nil if it fails.
- def load_gemspec(io)
- Gem::Specification.from_yaml io
- rescue Gem::Exception
- nil
- end
-
- ##
- # Return an IO stream for the zipped entry.
- #
- # NOTE: Originally this method used two approaches, Return a GZipReader
- # directly, or read the GZipReader into a string and return a StringIO on
- # the string. The string IO approach was used for versions of ZLib before
- # 1.2.1 to avoid buffer errors on windows machines. Then we found that
- # errors happened with 1.2.1 as well, so we changed the condition. Then
- # we discovered errors occurred with versions as late as 1.2.3. At this
- # point (after some benchmarking to show we weren't seriously crippling
- # the unpacking speed) we threw our hands in the air and declared that
- # this method would use the String IO approach on all platforms at all
- # times. And that's the way it is.
- #
- # Revisited. Here's the beginning of the long story.
- # http://osdir.com/ml/lang.ruby.gems.devel/2007-06/msg00045.html
- #
- # StringIO wraping has never worked as a workaround by definition. Skipping
- # initial 10 bytes and passing -MAX_WBITS to Zlib::Inflate luckily works as
- # gzip reader, but it only works if the GZip header is 10 bytes long (see
- # below) and it does not check inflated stream consistency (CRC value in the
- # Gzip trailer.)
- #
- # RubyGems generated Gzip Header: 10 bytes
- # magic(2) + method(1) + flag(1) + mtime(4) + exflag(1) + os(1) +
- # orig_name(0) + comment(0)
- #
- # Ideally, it must return a GZipReader without meaningless buffering. We
- # have lots of CRuby committers around so let's fix windows build when we
- # received an error.
- def zipped_stream(entry)
- Zlib::GzipReader.new entry
- end
-
-end
-
diff --git a/lib/rubygems/package/tar_output.rb b/lib/rubygems/package/tar_output.rb
deleted file mode 100644
index fdc8f4fb7c..0000000000
--- a/lib/rubygems/package/tar_output.rb
+++ /dev/null
@@ -1,146 +0,0 @@
-# -*- coding: utf-8 -*-
-#--
-# Copyright (C) 2004 Mauricio Julio Fernández Pradier
-# See LICENSE.txt for additional licensing information.
-#++
-
-##
-# TarOutput is a wrapper to TarWriter that builds gem-format tar file.
-#
-# Gem-format tar files contain the following files:
-# [data.tar.gz] A gzipped tar file containing the files that compose the gem
-# which will be extracted into the gem/ dir on installation.
-# [metadata.gz] A YAML format Gem::Specification.
-# [data.tar.gz.sig] A signature for the gem's data.tar.gz.
-# [metadata.gz.sig] A signature for the gem's metadata.gz.
-#
-# See TarOutput::open for usage details.
-
-class Gem::Package::TarOutput
-
- ##
- # Creates a new TarOutput which will yield a TarWriter object for the
- # data.tar.gz portion of a gem-format tar file.
- #
- # See #initialize for details on +io+ and +signer+.
- #
- # See #add_gem_contents for details on adding metadata to the tar file.
-
- def self.open(io, signer = nil, &block) # :yield: data_tar_writer
- tar_outputter = new io, signer
- tar_outputter.add_gem_contents(&block)
- tar_outputter.add_metadata
- tar_outputter.add_signatures
-
- ensure
- tar_outputter.close
- end
-
- ##
- # Creates a new TarOutput that will write a gem-format tar file to +io+. If
- # +signer+ is given, the data.tar.gz and metadata.gz will be signed and
- # the signatures will be added to the tar file.
-
- def initialize(io, signer)
- @io = io
- @signer = signer
-
- @tar_writer = Gem::Package::TarWriter.new @io
-
- @metadata = nil
-
- @data_signature = nil
- @meta_signature = nil
- end
-
- ##
- # Yields a TarWriter for the data.tar.gz inside a gem-format tar file.
- # The yielded TarWriter has been extended with a #metadata= method for
- # attaching a YAML format Gem::Specification which will be written by
- # add_metadata.
-
- def add_gem_contents
- @tar_writer.add_file "data.tar.gz", 0644 do |inner|
- sio = @signer ? StringIO.new : nil
- Zlib::GzipWriter.wrap(sio || inner) do |os|
-
- Gem::Package::TarWriter.new os do |data_tar_writer|
- # :stopdoc:
- def data_tar_writer.metadata() @metadata end
- def data_tar_writer.metadata=(metadata) @metadata = metadata end
- # :startdoc:
-
- yield data_tar_writer
-
- @metadata = data_tar_writer.metadata
- end
- end
-
- # if we have a signing key, then sign the data
- # digest and return the signature
- if @signer then
- require 'rubygems/security'
- digest = Gem::Security::OPT[:dgst_algo].digest sio.string
- @data_signature = @signer.sign digest
- inner.write sio.string
- end
- end
-
- self
- end
-
- ##
- # Adds metadata.gz to the gem-format tar file which was saved from a
- # previous #add_gem_contents call.
-
- def add_metadata
- return if @metadata.nil?
-
- @tar_writer.add_file "metadata.gz", 0644 do |io|
- begin
- sio = @signer ? StringIO.new : nil
- gzos = Zlib::GzipWriter.new(sio || io)
- gzos.write @metadata
- ensure
- gzos.flush
- gzos.finish
-
- # if we have a signing key, then sign the metadata digest and return
- # the signature
- if @signer then
- require 'rubygems/security'
- digest = Gem::Security::OPT[:dgst_algo].digest sio.string
- @meta_signature = @signer.sign digest
- io.write sio.string
- end
- end
- end
- end
-
- ##
- # Adds data.tar.gz.sig and metadata.gz.sig to the gem-format tar files if
- # a Gem::Security::Signer was sent to initialize.
-
- def add_signatures
- if @data_signature then
- @tar_writer.add_file 'data.tar.gz.sig', 0644 do |io|
- io.write @data_signature
- end
- end
-
- if @meta_signature then
- @tar_writer.add_file 'metadata.gz.sig', 0644 do |io|
- io.write @meta_signature
- end
- end
- end
-
- ##
- # Closes the TarOutput.
-
- def close
- @tar_writer.close
- end
-
-end
-
diff --git a/lib/rubygems/package/tar_reader.rb b/lib/rubygems/package/tar_reader.rb
index e6a71d386c..e257fdd846 100644
--- a/lib/rubygems/package/tar_reader.rb
+++ b/lib/rubygems/package/tar_reader.rb
@@ -9,7 +9,7 @@
class Gem::Package::TarReader
- include Gem::Package
+ include Enumerable
##
# Raised if the tar IO is not seekable
@@ -52,9 +52,9 @@ class Gem::Package::TarReader
# Iterates over files in the tarball yielding each entry
def each
- loop do
- return if @io.eof?
+ return enum_for __method__ unless block_given?
+ until @io.eof? do
header = Gem::Package::TarHeader.from @io
return if header.empty?
@@ -100,6 +100,23 @@ class Gem::Package::TarReader
end
end
+ ##
+ # Seeks through the tar file until it finds the +entry+ with +name+ and
+ # yields it. Rewinds the tar file to the beginning when the block
+ # terminates.
+
+ def seek name # :yields: entry
+ found = find do |entry|
+ entry.full_name == name
+ end
+
+ return unless found
+
+ return yield found
+ ensure
+ rewind
+ end
+
end
require 'rubygems/package/tar_reader/entry'
diff --git a/lib/rubygems/package/tar_writer.rb b/lib/rubygems/package/tar_writer.rb
index a73b5e5cab..f2c11e3544 100644
--- a/lib/rubygems/package/tar_writer.rb
+++ b/lib/rubygems/package/tar_writer.rb
@@ -40,12 +40,12 @@ class Gem::Package::TarWriter
# number of bytes will be more than #limit
def write(data)
- if data.size + @written > @limit
+ if data.bytesize + @written > @limit
raise FileOverflow, "You tried to feed more data than fits in the file."
end
@io.write data
- @written += data.size
- data.size
+ @written += data.bytesize
+ data.bytesize
end
end
@@ -130,6 +130,62 @@ class Gem::Package::TarWriter
end
##
+ # Adds +name+ with permissions +mode+ to the tar, yielding +io+ for writing
+ # the file. The +digest_algorithm+ is written to a read-only +name+.sum
+ # file following the given file contents containing the digest name and
+ # hexdigest separated by a tab.
+ #
+ # The created digest object is returned.
+
+ def add_file_digest name, mode, digest_algorithms # :yields: io
+ digests = digest_algorithms.map do |digest_algorithm|
+ digest = digest_algorithm.new
+ [digest.name, digest]
+ end
+
+ digests = Hash[*digests.flatten]
+
+ add_file name, mode do |io|
+ Gem::Package::DigestIO.wrap io, digests do |digest_io|
+ yield digest_io
+ end
+ end
+
+ digests
+ end
+
+ ##
+ # Adds +name+ with permissions +mode+ to the tar, yielding +io+ for writing
+ # the file. The +signer+ is used to add a digest file using its
+ # digest_algorithm per add_file_digest and a cryptographic signature in
+ # +name+.sig. If the signer has no key only the checksum file is added.
+ #
+ # Returns the digest.
+
+ def add_file_signed name, mode, signer
+ digest_algorithms = [
+ signer.digest_algorithm,
+ OpenSSL::Digest::SHA512,
+ ].uniq
+
+ digests = add_file_digest name, mode, digest_algorithms do |io|
+ yield io
+ end
+
+ signature_digest = digests.values.find do |digest|
+ digest.name == signer.digest_name
+ end
+
+ signature = signer.sign signature_digest.digest
+
+ add_file_simple "#{name}.sig", 0444, signature.length do |io|
+ io.write signature
+ end if signature
+
+ digests
+ end
+
+ ##
# Add file +name+ with permissions +mode+ +size+ bytes long. Yields an IO
# to write the file to.
@@ -211,9 +267,9 @@ class Gem::Package::TarWriter
# Splits +name+ into a name and prefix that can fit in the TarHeader
def split_name(name) # :nodoc:
- raise Gem::Package::TooLongFileName if name.size > 256
+ raise Gem::Package::TooLongFileName if name.bytesize > 256
- if name.size <= 100 then
+ if name.bytesize <= 100 then
prefix = ""
else
parts = name.split(/\//)
@@ -222,14 +278,14 @@ class Gem::Package::TarWriter
loop do
nxt = parts.pop
- break if newname.size + 1 + nxt.size > 100
+ break if newname.bytesize + 1 + nxt.bytesize > 100
newname = nxt + "/" + newname
end
prefix = (parts + [nxt]).join "/"
name = newname
- if name.size > 100 or prefix.size > 155 then
+ if name.bytesize > 100 or prefix.bytesize > 155 then
raise Gem::Package::TooLongFileName
end
end