rubygems-mirror 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,7 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ Autotest.add_hook :initialize do |at|
6
+ at.testlib = 'minitest/unit' if at.respond_to? :testlib=
7
+ end
data/.gemtest ADDED
File without changes
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,5 @@
1
+ === 1.0.0 / 2011-10-01
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
data/Manifest.txt ADDED
@@ -0,0 +1,12 @@
1
+ .autotest
2
+ CHANGELOG.rdoc
3
+ Manifest.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/rubygems/mirror.rb
7
+ lib/rubygems/mirror/command.rb
8
+ lib/rubygems/mirror/fetcher.rb
9
+ lib/rubygems/mirror/pool.rb
10
+ lib/rubygems/mirror/test_setup.rb
11
+ lib/rubygems_plugin.rb
12
+ test/test_gem_mirror.rb
data/README.rdoc ADDED
@@ -0,0 +1,70 @@
1
+ = rubygems-mirror
2
+
3
+ http://github.com/rubygems/rubygems-mirror
4
+
5
+ == DESCRIPTION:
6
+
7
+ This is an update to the old `gem mirror` command. It uses net/http/persistent
8
+ and threads to grab the mirror set a little faster than the original.
9
+ Eventually it will replace `gem mirror` completely. Right now the API is not
10
+ completely stable (it will change several times before release), however, I
11
+ will maintain stability in master.
12
+
13
+ == FEATURES/PROBLEMS:
14
+
15
+ * Fast mirroring
16
+ * Limited tests - just functional
17
+
18
+ == REQUIREMENTS:
19
+
20
+ * rubygems
21
+ * net/http/persistent
22
+
23
+ == USAGE
24
+
25
+ * In a file at ~/.gem/.mirrorrc add a config that looks like the following:
26
+
27
+ ---
28
+ - from: http://rubygems.org
29
+ to: /data/rubygems
30
+
31
+ * Either install the gem, then run `gem mirror`, or
32
+ * Clone then run `rake mirror:update`
33
+
34
+ == INSTALL:
35
+
36
+ * gem install rubygems-mirror
37
+
38
+ == RESOURCES
39
+
40
+ * {Website}[http://rubygems.org/]
41
+ * {Documentation}[http://rubygems.rubyforge.org/rubygems-mirror/README_rdoc.html]
42
+ * {Wiki}[http://wiki.github.com/rubygems/rubygems-mirror/]
43
+ * {Source Code}[http://github.com/rubygems/rubygems-mirror/]
44
+ * {Issues}[http://github.com/rubygems/rubygems-mirror/issues]
45
+ * {Rubyforge}[http://rubyforge.org/projects/rubygems]
46
+
47
+ == LICENSE:
48
+
49
+ (The MIT License)
50
+
51
+ Copyright (c) 2010 James Tucker, The RubyGems Team
52
+
53
+ Permission is hereby granted, free of charge, to any person obtaining
54
+ a copy of this software and associated documentation files (the
55
+ 'Software'), to deal in the Software without restriction, including
56
+ without limitation the rights to use, copy, modify, merge, publish,
57
+ distribute, sublicense, and/or sell copies of the Software, and to
58
+ permit persons to whom the Software is furnished to do so, subject to
59
+ the following conditions:
60
+
61
+ The above copyright notice and this permission notice shall be
62
+ included in all copies or substantial portions of the Software.
63
+
64
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
65
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
66
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
67
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
68
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
69
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
70
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'hoe'
4
+ Hoe.plugin :doofus, :git, :gemcutter
5
+
6
+ Hoe.spec 'rubygems-mirror' do
7
+ developer('James Tucker', 'raggi@rubyforge.org')
8
+
9
+ extra_dev_deps << %w[hoe-doofus >=1.0.0]
10
+ extra_dev_deps << %w[hoe-git >=1.3.0]
11
+ extra_dev_deps << %w[hoe-gemcutter >=1.0.0]
12
+ extra_dev_deps << %w[builder >=2.1.2]
13
+ extra_deps << %w[net-http-persistent >=2.1]
14
+
15
+ self.extra_rdoc_files = FileList["**/*.rdoc"]
16
+ self.history_file = "CHANGELOG.rdoc"
17
+ self.readme_file = "README.rdoc"
18
+ self.rubyforge_name = 'rubygems'
19
+ self.testlib = :minitest
20
+ end
21
+
22
+ namespace :mirror do
23
+ desc "Run the Gem::Mirror::Command"
24
+ task :update do
25
+ $:.unshift 'lib'
26
+ require 'rubygems/mirror/command'
27
+
28
+ mirror = Gem::Commands::MirrorCommand.new
29
+ mirror.execute
30
+ end
31
+ end
32
+
33
+ namespace :test do
34
+ task :integration do
35
+ sh Gem.ruby, '-Ilib', '-rubygems', '-S', 'gem', 'mirror'
36
+ end
37
+ end
@@ -0,0 +1,88 @@
1
+ require 'rubygems'
2
+ require 'fileutils'
3
+
4
+ class Gem::Mirror
5
+ autoload :Fetcher, 'rubygems/mirror/fetcher'
6
+ autoload :Pool, 'rubygems/mirror/pool'
7
+
8
+ VERSION = '1.0.0'
9
+
10
+ SPECS_FILE = "specs.#{Gem.marshal_version}"
11
+ SPECS_FILE_Z = "specs.#{Gem.marshal_version}.gz"
12
+
13
+ DEFAULT_URI = 'http://production.cf.rubygems.org/'
14
+ DEFAULT_TO = File.join(Gem.user_home, '.gem', 'mirror')
15
+
16
+ RUBY = 'ruby'
17
+
18
+ def initialize(from = DEFAULT_URI, to = DEFAULT_TO, parallelism = 10)
19
+ @from, @to = from, to
20
+ @fetcher = Fetcher.new
21
+ @pool = Pool.new(parallelism)
22
+ end
23
+
24
+ def from(*args)
25
+ File.join(@from, *args)
26
+ end
27
+
28
+ def to(*args)
29
+ File.join(@to, *args)
30
+ end
31
+
32
+ def update_specs
33
+ specz = to(SPECS_FILE_Z)
34
+ @fetcher.fetch(from(SPECS_FILE_Z), specz)
35
+ open(to(SPECS_FILE), 'wb') { |f| f << Gem.gunzip(File.read(specz)) }
36
+ end
37
+
38
+ def gems
39
+ update_specs unless File.exists?(to(SPECS_FILE))
40
+
41
+ gems = Marshal.load(File.read(to(SPECS_FILE)))
42
+ gems.map! do |name, ver, plat|
43
+ # If the platform is ruby, it is not in the gem name
44
+ "#{name}-#{ver}#{"-#{plat}" unless plat == RUBY}.gem"
45
+ end
46
+ gems
47
+ end
48
+
49
+ def existing_gems
50
+ Dir[to('gems', '*.gem')].entries.map { |f| File.basename(f) }
51
+ end
52
+
53
+ def gems_to_fetch
54
+ gems - existing_gems
55
+ end
56
+
57
+ def gems_to_delete
58
+ existing_gems - gems
59
+ end
60
+
61
+ def update_gems
62
+ gems_to_fetch.each do |g|
63
+ @pool.job do
64
+ @fetcher.fetch(from('gems', g), to('gems', g))
65
+ yield
66
+ end
67
+ end
68
+
69
+ @pool.run_til_done
70
+ end
71
+
72
+ def delete_gems
73
+ gems_to_delete.each do |g|
74
+ @pool.job do
75
+ File.delete(to('gems', g))
76
+ yield
77
+ end
78
+ end
79
+
80
+ @pool.run_til_done
81
+ end
82
+
83
+ def update
84
+ update_specs
85
+ update_gems
86
+ cleanup_gems
87
+ end
88
+ end
@@ -0,0 +1,71 @@
1
+ require 'rubygems/mirror'
2
+ require 'rubygems/command'
3
+ require 'yaml'
4
+
5
+ class Gem::Commands::MirrorCommand < Gem::Command
6
+ SUPPORTS_INFO_SIGNAL = Signal.list['INFO']
7
+
8
+ def initialize
9
+ super 'mirror', 'Mirror a gem repository'
10
+ end
11
+
12
+ def description # :nodoc:
13
+ <<-EOF
14
+ The mirror command uses the ~/.gemmirrorrc config file to mirror remote gem
15
+ repositories to a local path. The config file is a YAML document that looks
16
+ like this:
17
+
18
+ ---
19
+ - from: http://gems.example.com # source repository URI
20
+ to: /path/to/mirror # destination directory
21
+
22
+ Multiple sources and destinations may be specified.
23
+ EOF
24
+ end
25
+
26
+ def execute
27
+ config_file = File.join Gem.user_home, '.gem', '.mirrorrc'
28
+
29
+ raise "Config file #{config_file} not found" unless File.exist? config_file
30
+
31
+ mirrors = YAML.load_file config_file
32
+
33
+ raise "Invalid config file #{config_file}" unless mirrors.respond_to? :each
34
+
35
+ mirrors.each do |mir|
36
+ raise "mirror missing 'from' field" unless mir.has_key? 'from'
37
+ raise "mirror missing 'to' field" unless mir.has_key? 'to'
38
+
39
+ get_from = mir['from']
40
+ save_to = File.expand_path mir['to']
41
+
42
+ raise "Directory not found: #{save_to}" unless File.exist? save_to
43
+ raise "Not a directory: #{save_to}" unless File.directory? save_to
44
+
45
+ mirror = Gem::Mirror.new(get_from, save_to)
46
+
47
+ say "Fetching: #{mirror.from(Gem::Mirror::SPECS_FILE_Z)}"
48
+ mirror.update_specs
49
+
50
+ say "Total gems: #{mirror.gems.size}"
51
+
52
+ num_to_fetch = mirror.gems_to_fetch.size
53
+
54
+ progress = ui.progress_reporter num_to_fetch,
55
+ "Fetching #{num_to_fetch} gems"
56
+
57
+ trap(:INFO) { puts "Fetched: #{progress.count}/#{num_to_fetch}" } if SUPPORTS_INFO_SIGNAL
58
+
59
+ mirror.update_gems { progress.updated true }
60
+
61
+ num_to_delete = mirror.gems_to_delete.size
62
+
63
+ progress = ui.progress_reporter num_to_delete,
64
+ "Deleting #{num_to_delete} gems"
65
+
66
+ trap(:INFO) { puts "Fetched: #{progress.count}/#{num_to_delete}" } if SUPPORTS_INFO_SIGNAL
67
+
68
+ mirror.delete_gems { progress.updated true }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,56 @@
1
+ require 'net/http/persistent'
2
+ require 'time'
3
+
4
+ class Gem::Mirror::Fetcher
5
+ # TODO beef
6
+ class Error < StandardError; end
7
+
8
+ def initialize
9
+ @http = Net::HTTP::Persistent.new(self.class.name, :ENV)
10
+ end
11
+
12
+ # Fetch a source path under the base uri, and put it in the same or given
13
+ # destination path under the base path.
14
+ def fetch(uri, path)
15
+ modified_time = File.exists?(path) && File.stat(path).mtime.rfc822
16
+
17
+ req = Net::HTTP::Get.new URI.parse(uri).path
18
+ req.add_field 'If-Modified-Since', modified_time if modified_time
19
+
20
+ @http.request URI(uri), req do |resp|
21
+ return handle_response(resp, path)
22
+ end
23
+ end
24
+
25
+ # Handle an http response, follow redirects, etc. returns true if a file was
26
+ # downloaded, false if a 304. Raise Error on unknown responses.
27
+ def handle_response(resp, path)
28
+ case resp.code.to_i
29
+ when 304
30
+ when 302
31
+ fetch resp['location'], path
32
+ when 200
33
+ write_file(resp, path)
34
+ when 403, 404
35
+ warn "#{resp.code} on #{File.basename(path)}"
36
+ else
37
+ raise Error, "unexpected response #{resp.inspect}"
38
+ end
39
+ # TODO rescue http errors and reraise cleanly
40
+ end
41
+
42
+ # Efficiently writes an http response object to a particular path. If there
43
+ # is an error, it will remove the target file.
44
+ def write_file(resp, path)
45
+ FileUtils.mkdir_p File.dirname(path)
46
+ File.open(path, 'wb') do |output|
47
+ resp.read_body { |chunk| output << chunk }
48
+ end
49
+ true
50
+ ensure
51
+ # cleanup incomplete files, rescue perm errors etc, they're being
52
+ # raised already.
53
+ File.delete(path) rescue nil if $!
54
+ end
55
+
56
+ end
@@ -0,0 +1,22 @@
1
+ require 'thread'
2
+
3
+ class Gem::Mirror::Pool
4
+ def initialize(size)
5
+ @size = size
6
+ @queue = Queue.new
7
+ end
8
+
9
+ def job(&blk)
10
+ @queue << blk
11
+ end
12
+
13
+ def run_til_done
14
+ threads = Array.new(@size) do
15
+ Thread.new { @queue.pop.call while true }
16
+ end
17
+ until @queue.empty? && @queue.num_waiting == @size
18
+ threads.each { |t| t.join(0.1) }
19
+ end
20
+ threads.each { |t| t.kill }
21
+ end
22
+ end
@@ -0,0 +1,166 @@
1
+ require 'tempfile'
2
+ require 'fileutils'
3
+ require 'stringio'
4
+ require 'webrick'
5
+
6
+ require "rubygems/user_interaction"
7
+ require "rubygems/indexer"
8
+
9
+ # All files must be proactively loaded, otherwhise when the Gem index is
10
+ # replaced, requires will fail!
11
+ require "rubygems/mirror"
12
+ require "rubygems/mirror/fetcher"
13
+ require "rubygems/mirror/pool"
14
+
15
+ class Gem::Mirror
16
+
17
+ # Provide assistance for authors of code that utilises Gem::Mirror. The
18
+ # module defines several setup and teardown methods that can be used to
19
+ # provide a new gem source on disk.
20
+ module TestSetup
21
+ # An instance of TestSetup::UI, a mock UI for RubyGems.
22
+ attr_reader :ui
23
+
24
+ # The path in which setup_gem_source will place a RubyGems source index
25
+ attr_reader :source_path
26
+
27
+ # A list of gem names in the source_path
28
+ attr_reader :source_gems
29
+
30
+ # A temporary directory where mirrors might put their data
31
+ attr_reader :mirror_path
32
+
33
+ # An rcfile pointing at the source and mirror paths
34
+ attr_reader :mirrorrc
35
+
36
+ # Path to the mock, temporary mirrorrc
37
+ attr_reader :mirrorrc_path
38
+
39
+ class UI < Gem::StreamUI
40
+
41
+ # All input and output from the Gem UI when using TestSetup will pass
42
+ # through StringIO objects placed here. For more information, see the
43
+ # arguments to Gem::StreamUI.
44
+ attr_reader :ui_ios
45
+
46
+ def initialize
47
+ super(*(@ui_ios = Array.new(3) { StringIO.new }))
48
+ end
49
+ end
50
+
51
+ # Setup a new mock UI using TestSetup::UI
52
+ def setup_ui
53
+ @old_ui = Gem::DefaultUserInteraction.ui
54
+ @ui = Gem::DefaultUserInteraction.ui = UI.new
55
+ end
56
+
57
+ # Restore RubyGems default UI
58
+ def teardown_ui
59
+ Gem::DefaultUserInteraction.ui = @old_ui if @old_ui
60
+ end
61
+
62
+ # Setup a new gem source directory containing a few gems suitable for
63
+ # testing mirrors, and place the path to that in source_path.
64
+ def setup_gem_source
65
+ @source_path = Dir.mktmpdir("test_gem_source_path_#{$$}")
66
+
67
+ Dir.mkdir gemdir = File.join(@source_path, 'gems')
68
+
69
+ @source_working = working = Dir.mktmpdir("test_gem_source_#{$$}")
70
+
71
+ Dir.mkdir File.join(working, 'lib')
72
+
73
+ gemspecs = %w[a b c].map do |name|
74
+ FileUtils.touch File.join(working, 'lib', "#{name}.rb")
75
+ Gem::Specification.new do |s|
76
+ s.platform = Gem::Platform::RUBY
77
+ s.name = name
78
+ s.version = 1.0
79
+ s.author = 'rubygems'
80
+ s.email = 'example@example.com'
81
+ s.homepage = 'http://example.com'
82
+ s.has_rdoc = false
83
+ s.description = 'desc'
84
+ s.summary = "summ"
85
+ s.require_paths = %w[lib]
86
+ s.files = %W[lib/#{name}.rb]
87
+ s.rubyforge_project = 'rubygems'
88
+ end
89
+ end
90
+
91
+ gemspecs.each do |spec|
92
+ path = File.join(working, "#{spec.name}.gemspec")
93
+ open(path, 'w') do |io|
94
+ io.write(spec.to_ruby)
95
+ end
96
+ Dir.chdir(working) do
97
+ gem_file = Gem::Builder.new(spec).build
98
+ FileUtils.mv(gem_file, File.join(@source_path, 'gems', gem_file))
99
+ end
100
+ end
101
+
102
+ @source_gems = Dir[File.join(gemdir, '*.gem')].map {|p|File.basename(p)}
103
+
104
+ Gem::Indexer.new(@source_path).generate_index
105
+ end
106
+
107
+ # Cleanup temporary directories that are created by setup_gem_source.
108
+ def teardown_gem_source
109
+ [@source_path, @source_working].each do |path|
110
+ FileUtils.rm_rf path
111
+ end
112
+ end
113
+
114
+ # Setup a new mirrorrc for Gem::Mirror based on a setup from
115
+ # setup_gem_source.
116
+ def setup_mirrorrc
117
+ @mirror_path = Dir.mktmpdir("test_gem_mirror_path_#{$$}")
118
+ @mirrorrc = Tempfile.new('testgemmirrorrc')
119
+ opts = {
120
+ 'mirrors' => {
121
+ 'from' => "http://127.0.0.1:8808/", 'to' => @mirror_path
122
+ }
123
+ }
124
+ @mirrorrc.write YAML.dump(opts)
125
+ @mirrorrc_path = @mirrorrc.path
126
+ end
127
+
128
+ # Cleanup tempfiles created by setup_mirrorrc.
129
+ def teardown_mirrorrc
130
+ FileUtils.rm_rf @mirrorrc_path if @mirrorrc_path
131
+ FileUtils.rm_rf @mirror_path if @mirror_path
132
+ end
133
+
134
+ # Starts a server using Rack that will host the gem source
135
+ def setup_server
136
+ opts = { :Port => 8808, :DocumentRoot => @source_path }
137
+ unless $DEBUG
138
+ require 'logger'
139
+ opts[:Logger] = Logger.new('/dev/null')
140
+ opts[:AccessLog] = Logger.new('/dev/null')
141
+ end
142
+ @server = WEBrick::HTTPServer.new opts
143
+ @server_thread = Thread.new { @server.start }
144
+ @server_thread.join(0.1) # pickup early errors and give it time to start
145
+ end
146
+
147
+ # Shutdown the local server hosting the source_path
148
+ def teardown_server
149
+ @server && @server.shutdown
150
+ @server_thread && @server_thread.join
151
+ end
152
+
153
+ def with_server
154
+ setup_ui
155
+ setup_gem_source
156
+ setup_mirrorrc
157
+ setup_server
158
+ yield
159
+ ensure
160
+ teardown_gem_source
161
+ teardown_server
162
+ teardown_mirrorrc
163
+ teardown_ui
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubygems/command_manager'
2
+ require 'rubygems/mirror/command'
3
+
4
+ Gem::CommandManager.instance.register_command :mirror
@@ -0,0 +1,5 @@
1
+ === 1.0.0 / 2011-10-01
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
@@ -0,0 +1,70 @@
1
+ = rubygems-mirror
2
+
3
+ http://github.com/rubygems/rubygems-mirror
4
+
5
+ == DESCRIPTION:
6
+
7
+ This is an update to the old `gem mirror` command. It uses net/http/persistent
8
+ and threads to grab the mirror set a little faster than the original.
9
+ Eventually it will replace `gem mirror` completely. Right now the API is not
10
+ completely stable (it will change several times before release), however, I
11
+ will maintain stability in master.
12
+
13
+ == FEATURES/PROBLEMS:
14
+
15
+ * Fast mirroring
16
+ * Limited tests - just functional
17
+
18
+ == REQUIREMENTS:
19
+
20
+ * rubygems
21
+ * net/http/persistent
22
+
23
+ == USAGE
24
+
25
+ * In a file at ~/.gem/.mirrorrc add a config that looks like the following:
26
+
27
+ ---
28
+ - from: http://rubygems.org
29
+ to: /data/rubygems
30
+
31
+ * Either install the gem, then run `gem mirror`, or
32
+ * Clone then run `rake mirror:update`
33
+
34
+ == INSTALL:
35
+
36
+ * gem install rubygems-mirror
37
+
38
+ == RESOURCES
39
+
40
+ * {Website}[http://rubygems.org/]
41
+ * {Documentation}[http://rubygems.rubyforge.org/rubygems-mirror/README_rdoc.html]
42
+ * {Wiki}[http://wiki.github.com/rubygems/rubygems-mirror/]
43
+ * {Source Code}[http://github.com/rubygems/rubygems-mirror/]
44
+ * {Issues}[http://github.com/rubygems/rubygems-mirror/issues]
45
+ * {Rubyforge}[http://rubyforge.org/projects/rubygems]
46
+
47
+ == LICENSE:
48
+
49
+ (The MIT License)
50
+
51
+ Copyright (c) 2010 James Tucker, The RubyGems Team
52
+
53
+ Permission is hereby granted, free of charge, to any person obtaining
54
+ a copy of this software and associated documentation files (the
55
+ 'Software'), to deal in the Software without restriction, including
56
+ without limitation the rights to use, copy, modify, merge, publish,
57
+ distribute, sublicense, and/or sell copies of the Software, and to
58
+ permit persons to whom the Software is furnished to do so, subject to
59
+ the following conditions:
60
+
61
+ The above copyright notice and this permission notice shall be
62
+ included in all copies or substantial portions of the Software.
63
+
64
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
65
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
66
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
67
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
68
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
69
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
70
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,54 @@
1
+ require "rubygems_plugin"
2
+ require "rubygems/mirror"
3
+ require "rubygems/mirror/test_setup"
4
+
5
+ require 'minitest/autorun' # damn you autotest.
6
+
7
+ class TestGemMirror < MiniTest::Unit::TestCase
8
+ include Gem::Mirror::TestSetup
9
+
10
+ # Used to make sure we don't raise on construction, works against defaults
11
+ def opts
12
+ ['http://localhost:8808/', mirror_path, 1]
13
+ end
14
+
15
+ def test_update_specs
16
+ with_server do
17
+ mirror = Gem::Mirror.new(*opts)
18
+ mirror.update_specs
19
+ assert File.exists?(mirror_path + "/#{Gem::Mirror::SPECS_FILE_Z}")
20
+ assert File.exists?(mirror_path + "/#{Gem::Mirror::SPECS_FILE_Z}")
21
+ end
22
+ end
23
+
24
+ def test_update_gems
25
+ with_server do
26
+ mirror = Gem::Mirror.new(*opts)
27
+
28
+ updates = 0
29
+ mirror.update_gems { updates += 1 }
30
+
31
+ source_gems, mirror_gems = [source_path, mirror_path].map do |path|
32
+ Dir[path + '/gems/*'].map { |f| File.basename(f) }
33
+ end
34
+
35
+ assert_equal source_gems, mirror_gems
36
+ assert_equal 3, updates
37
+ end
38
+ end
39
+
40
+ def test_delete_gems
41
+ with_server do
42
+ mirror = Gem::Mirror.new(*opts)
43
+ FileUtils.mkdir_p mirror.to('gems')
44
+ FileUtils.touch mirror.to('gems', 'd-1.0.gem')
45
+
46
+ updates = 0
47
+ mirror.delete_gems { updates += 1 }
48
+
49
+ gems = Dir[mirror_path + '/gems/*.gem'].map { |f| File.basename f }
50
+ assert_equal [], gems
51
+ assert_equal 1, updates
52
+ end
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubygems-mirror
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - James Tucker
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-10-02 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: net-http-persistent
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 1
29
+ segments:
30
+ - 2
31
+ - 1
32
+ version: "2.1"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe-doofus
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 23
44
+ segments:
45
+ - 1
46
+ - 0
47
+ - 0
48
+ version: 1.0.0
49
+ type: :development
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: hoe-git
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 27
60
+ segments:
61
+ - 1
62
+ - 3
63
+ - 0
64
+ version: 1.3.0
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: hoe-gemcutter
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 23
76
+ segments:
77
+ - 1
78
+ - 0
79
+ - 0
80
+ version: 1.0.0
81
+ type: :development
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ name: builder
85
+ prerelease: false
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 15
92
+ segments:
93
+ - 2
94
+ - 1
95
+ - 2
96
+ version: 2.1.2
97
+ type: :development
98
+ version_requirements: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ name: hoe
101
+ prerelease: false
102
+ requirement: &id006 !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ~>
106
+ - !ruby/object:Gem::Version
107
+ hash: 27
108
+ segments:
109
+ - 2
110
+ - 12
111
+ version: "2.12"
112
+ type: :development
113
+ version_requirements: *id006
114
+ description: |-
115
+ This is an update to the old `gem mirror` command. It uses net/http/persistent
116
+ and threads to grab the mirror set a little faster than the original.
117
+ Eventually it will replace `gem mirror` completely. Right now the API is not
118
+ completely stable (it will change several times before release), however, I
119
+ will maintain stability in master.
120
+ email:
121
+ - raggi@rubyforge.org
122
+ executables: []
123
+
124
+ extensions: []
125
+
126
+ extra_rdoc_files:
127
+ - Manifest.txt
128
+ - CHANGELOG.rdoc
129
+ - pkg/rubygems-mirror-1.0.0/CHANGELOG.rdoc
130
+ - pkg/rubygems-mirror-1.0.0/README.rdoc
131
+ - README.rdoc
132
+ files:
133
+ - .autotest
134
+ - CHANGELOG.rdoc
135
+ - Manifest.txt
136
+ - README.rdoc
137
+ - Rakefile
138
+ - lib/rubygems/mirror.rb
139
+ - lib/rubygems/mirror/command.rb
140
+ - lib/rubygems/mirror/fetcher.rb
141
+ - lib/rubygems/mirror/pool.rb
142
+ - lib/rubygems/mirror/test_setup.rb
143
+ - lib/rubygems_plugin.rb
144
+ - test/test_gem_mirror.rb
145
+ - pkg/rubygems-mirror-1.0.0/CHANGELOG.rdoc
146
+ - pkg/rubygems-mirror-1.0.0/README.rdoc
147
+ - .gemtest
148
+ homepage: http://github.com/rubygems/rubygems-mirror
149
+ licenses: []
150
+
151
+ metadata: {}
152
+
153
+ post_install_message:
154
+ rdoc_options:
155
+ - --main
156
+ - README.rdoc
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ none: false
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ hash: 3
165
+ segments:
166
+ - 0
167
+ version: "0"
168
+ required_rubygems_version: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ hash: 3
174
+ segments:
175
+ - 0
176
+ version: "0"
177
+ requirements: []
178
+
179
+ rubyforge_project: rubygems
180
+ rubygems_version: 1.8.10
181
+ signing_key:
182
+ specification_version: 4
183
+ summary: This is an update to the old `gem mirror` command
184
+ test_files:
185
+ - test/test_gem_mirror.rb