Permalink
Browse files

Initial version.

  • Loading branch information...
1 parent bc9af00 commit cff0fe5b013cd4cc925003ba689d861f819564c0 @pwnall committed Nov 19, 2010
Showing with 232 additions and 10 deletions.
  1. +12 −0 .project
  2. +1 −3 Gemfile
  3. +28 −0 Gemfile.lock
  4. +22 −3 README.rdoc
  5. +1 −1 Rakefile
  6. +21 −0 bin/gem-index-dumper
  7. +51 −0 lib/gem-index-dumper.rb
  8. +96 −3 spec/gem-index-dumper_spec.rb
View
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>gem-index-dumper</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ <nature>com.aptana.ruby.core.rubynature</nature>
+ </natures>
+</projectDescription>
View
@@ -1,7 +1,5 @@
source "http://rubygems.org"
-# Add dependencies required to use your gem here.
-# Example:
-# gem "activesupport", ">= 2.3.5"
+gem "bundler", "~> 1.0.0"
# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.
View
@@ -0,0 +1,28 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ diff-lcs (1.1.2)
+ git (1.2.5)
+ jeweler (1.5.1)
+ bundler (~> 1.0.0)
+ git (>= 1.2.5)
+ rake
+ rake (0.8.7)
+ rcov (0.9.9)
+ rspec (2.1.0)
+ rspec-core (~> 2.1.0)
+ rspec-expectations (~> 2.1.0)
+ rspec-mocks (~> 2.1.0)
+ rspec-core (2.1.0)
+ rspec-expectations (2.1.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.1.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ bundler (~> 1.0.0)
+ jeweler (~> 1.5.1)
+ rcov
+ rspec (~> 2.1.0)
View
@@ -1,6 +1,26 @@
= gem-index-dumper
-Description goes here.
+Spot-checks on the gem index.
+
+== Usage
+
+The gem installs a command-line tool gem-index-dumper which can be used as
+follows.
+
+ gem-index-dumper
+
+Dumps all the gem index entry (all gems, all versions, all platforms).
+
+ gem-index-dumper ^a
+
+Selects the gems starting with a and dumps the latest version of each gem,
+together with SHA-1s for the gem files.
+
+ gem-index-dumper ^a \\.0$
+
+Selects the gems starting with a and dumps the versions of each gem that end
+in .0 (e.g. 1.0, 2.0, 3.1.0), together with SHA-1s for the gem files.
+
== Contributing to gem-index-dumper
@@ -14,6 +34,5 @@ Description goes here.
== Copyright
-Copyright (c) 2010 Victor Costan. See LICENSE.txt for
-further details.
+Copyright (c) 2010 Victor Costan. See LICENSE.txt for further details.
View
@@ -21,7 +21,7 @@ Jeweler::Tasks.new do |gem|
gem.authors = ["Victor Costan"]
# Include your dependencies below. Runtime dependencies are required when using your gem,
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
- # gem.add_runtime_dependency 'jabber4r', '> 0.1'
+ gem.add_runtime_dependency 'bundler', '~> 1.0.0'
# gem.add_development_dependency 'rspec', '> 1.2.3'
end
Jeweler::RubygemsDotOrgTasks.new
View
@@ -0,0 +1,21 @@
+#!/usr/bin/env ruby
+require 'rubygems'
+require 'gem-index-dumper'
+
+case ARGV.length
+when 0
+ print GemIndexDumper.dump_remote_gems
+when 1
+ print GemIndexDumper.dump_gem_digests Regexp.new(ARGV[0])
+when 2
+ print GemIndexDumper.dump_gem_digests Regexp.new(ARGV[0]), Regexp.new(ARGV[1])
+else
+ print <<END
+Usage: #{$0} [name_pattern] [version_pattern]
+
+If no pattern is given, dumps all the gem entries in the index.
+
+If a name pattern is given, dumps the SHA-1 hash of the latest version for each
+gem whose name matches the pattern.
+END
+end
@@ -0,0 +1,51 @@
+require 'digest/sha1'
+require 'fileutils'
+require 'tempfile'
+
+require 'rubygems'
+require 'bundler'
+
+module GemIndexDumper
+ def self.all_remote_gems
+ Gem::SpecFetcher.new.list(true, true).values.first
+ end
+
+ def self.dump_remote_gems(pattern = nil)
+ gems = all_remote_gems
+ gems.sort!
+ gems.map { |data| "#{data[0]} / #{data[2]} v#{data[1].to_s}\n" }.join
+ end
+
+ def self.gem_digest(info)
+ uri = Gem.sources.first
+ spec = Bundler::RemoteSpecification.new(info[0], info[1], info[2], uri)
+ gem_file = Tempfile.new 'gem'
+ gem_path = gem_file.path
+ gem_file.close true
+
+ download_path = File.join(gem_path, 'cache')
+ FileUtils.mkdir_p download_path
+ gem_file = Gem::RemoteFetcher.fetcher.download(spec, uri, gem_path)
+ digest = Digest::SHA1.hexdigest File.read(gem_file)
+ FileUtils.rm_r gem_path
+ digest
+ end
+
+ def self.dump_gem_digests(name_pattern, version_pattern = nil)
+ gems = all_remote_gems.select { |data| name_pattern =~ data[0] }
+ gems.sort!
+ if version_pattern
+ gems = gems.select { |data| version_pattern =~ data[1].to_s }
+ else
+ # Pick the most recent gems.
+ gems_by_name = {}
+ gems.each { |data| gems_by_name[data[0]] = data }
+ gems = gems_by_name.values
+ gems.sort!
+ end
+
+ gems.map { |data|
+ "#{data[0]} / #{data[2]} v#{data[1].to_s} = #{gem_digest(data)}\n"
+ }.join
+ end
+end
@@ -1,7 +1,100 @@
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
-describe "GemIndexDumper" do
- it "fails" do
- fail "hey buddy, you should probably rename this file and start specing for real"
+describe 'GemIndexDumper' do
+ describe 'gem_digest' do
+ let(:gem_info) { ['activerecord', Gem::Version.new('3.0.0'), 'ruby'] }
+ it 'should compute the digest correctly' do
+ GemIndexDumper.gem_digest(gem_info).should ==
+ 'b4025f8396c9d784b26fa22c0dbf27e80a513469'
+ end
+ end
+
+ describe 'all_remote_gems' do
+ before :all do
+ @all = GemIndexDumper.all_remote_gems
+ end
+
+ it 'should include all versions for all gems' do
+ @all.should include(['activerecord', Gem::Version.new('3.0.0'), 'ruby'])
+ @all.should include(['activerecord', Gem::Version.new('3.0.3'), 'ruby'])
+ end
+ end
+
+ describe 'dump_remote_gems' do
+ before do
+ GemIndexDumper.should_receive(:all_remote_gems).and_return([
+ ['activerecord', Gem::Version.new('3.0.2'), 'ruby'],
+ ['activerecord', Gem::Version.new('3.0.3'), 'ruby'],
+ ['activerecord', Gem::Version.new('3.0.0'), 'ruby'],
+ ['activerecord', Gem::Version.new('3.0.1'), 'ruby'],
+ ['actionpack', Gem::Version.new('3.0.1'), 'ruby'],
+ ['actionpack', Gem::Version.new('3.0.0'), 'ruby'],
+ ['actionpack', Gem::Version.new('3.0.2'), 'ruby'],
+ ['actionpack', Gem::Version.new('2.3.5'), 'ruby']
+ ])
+ end
+
+ it 'without an argument should return all gems sorted' do
+ GemIndexDumper.dump_remote_gems.should == <<END
+actionpack / ruby v2.3.5
+actionpack / ruby v3.0.0
+actionpack / ruby v3.0.1
+actionpack / ruby v3.0.2
+activerecord / ruby v3.0.0
+activerecord / ruby v3.0.1
+activerecord / ruby v3.0.2
+activerecord / ruby v3.0.3
+END
+ end
+ end
+
+ describe 'dump_gem_digests' do
+ before do
+ GemIndexDumper.should_receive(:all_remote_gems).and_return([
+ ['activerecord', Gem::Version.new('3.0.2'), 'ruby'],
+ ['activerecord', Gem::Version.new('3.0.3'), 'ruby'],
+ ['activerecord', Gem::Version.new('3.0.0'), 'ruby'],
+ ['activerecord', Gem::Version.new('3.0.1'), 'ruby'],
+ ['actionpack', Gem::Version.new('3.0.1'), 'ruby'],
+ ['actionpack', Gem::Version.new('3.0.0'), 'ruby'],
+ ['actionpack', Gem::Version.new('3.0.2'), 'ruby'],
+ ['actionpack', Gem::Version.new('2.3.5'), 'ruby']
+ ])
+ GemIndexDumper.stub!(:gem_digest).
+ with(['actionpack', Gem::Version.new('3.0.2'), 'ruby']).
+ and_return('0011001100110011001100110011001100110011')
+ GemIndexDumper.stub!(:gem_digest).
+ with(['activerecord', Gem::Version.new('3.0.3'), 'ruby']).
+ and_return('2233223322332233223322332233223322332233')
+ GemIndexDumper.stub!(:gem_digest).
+ with(['activerecord', Gem::Version.new('3.0.2'), 'ruby']).
+ and_return('4455445544554455445544554455445544554455')
+ end
+
+ it 'without a version pattern should return the latest gem versions' do
+ GemIndexDumper.dump_gem_digests(/.*/).should == <<END
+actionpack / ruby v3.0.2 = 0011001100110011001100110011001100110011
+activerecord / ruby v3.0.3 = 2233223322332233223322332233223322332233
+END
+ end
+
+ it 'with a version pattern should return specific versions' do
+ GemIndexDumper.dump_gem_digests(/.*/, /2$/).should == <<END
+actionpack / ruby v3.0.2 = 0011001100110011001100110011001100110011
+activerecord / ruby v3.0.2 = 4455445544554455445544554455445544554455
+END
+ end
+
+ it 'with a name pattern should return the latest version' do
+ GemIndexDumper.dump_gem_digests(/pack/).should == <<END
+actionpack / ruby v3.0.2 = 0011001100110011001100110011001100110011
+END
+ end
+
+ it 'with name and version patterns should return that version' do
+ GemIndexDumper.dump_gem_digests(/record/, /2$/).should == <<END
+activerecord / ruby v3.0.2 = 4455445544554455445544554455445544554455
+END
+ end
end
end

0 comments on commit cff0fe5

Please sign in to comment.