2007-11-10 02:48:56 -05:00
|
|
|
require 'yaml'
|
|
|
|
require 'zlib'
|
|
|
|
|
|
|
|
require 'rubygems/command'
|
2008-03-31 18:40:06 -04:00
|
|
|
require 'open-uri'
|
2007-11-10 02:48:56 -05:00
|
|
|
|
|
|
|
class Gem::Commands::MirrorCommand < Gem::Command
|
|
|
|
|
|
|
|
def initialize
|
|
|
|
super 'mirror', 'Mirror a gem repository'
|
|
|
|
end
|
|
|
|
|
|
|
|
def description # :nodoc:
|
|
|
|
<<-EOF
|
|
|
|
The mirror command uses the ~/.gemmirrorrc config file to mirror remote gem
|
|
|
|
repositories to a local path. The config file is a YAML document that looks
|
|
|
|
like this:
|
|
|
|
|
|
|
|
---
|
|
|
|
- from: http://gems.example.com # source repository URI
|
|
|
|
to: /path/to/mirror # destination directory
|
|
|
|
|
|
|
|
Multiple sources and destinations may be specified.
|
|
|
|
EOF
|
|
|
|
end
|
|
|
|
|
|
|
|
def execute
|
|
|
|
config_file = File.join Gem.user_home, '.gemmirrorrc'
|
|
|
|
|
|
|
|
raise "Config file #{config_file} not found" unless File.exist? config_file
|
|
|
|
|
|
|
|
mirrors = YAML.load_file config_file
|
|
|
|
|
|
|
|
raise "Invalid config file #{config_file}" unless mirrors.respond_to? :each
|
|
|
|
|
|
|
|
mirrors.each do |mir|
|
|
|
|
raise "mirror missing 'from' field" unless mir.has_key? 'from'
|
|
|
|
raise "mirror missing 'to' field" unless mir.has_key? 'to'
|
|
|
|
|
|
|
|
get_from = mir['from']
|
|
|
|
save_to = File.expand_path mir['to']
|
|
|
|
|
|
|
|
raise "Directory not found: #{save_to}" unless File.exist? save_to
|
|
|
|
raise "Not a directory: #{save_to}" unless File.directory? save_to
|
|
|
|
|
|
|
|
gems_dir = File.join save_to, "gems"
|
|
|
|
|
|
|
|
if File.exist? gems_dir then
|
|
|
|
raise "Not a directory: #{gems_dir}" unless File.directory? gems_dir
|
|
|
|
else
|
|
|
|
Dir.mkdir gems_dir
|
|
|
|
end
|
|
|
|
|
2010-02-21 21:52:35 -05:00
|
|
|
source_index_data = ''
|
2007-11-10 02:48:56 -05:00
|
|
|
|
|
|
|
say "fetching: #{get_from}/Marshal.#{Gem.marshal_version}.Z"
|
|
|
|
|
|
|
|
get_from = URI.parse get_from
|
|
|
|
|
|
|
|
if get_from.scheme.nil? then
|
|
|
|
get_from = get_from.to_s
|
|
|
|
elsif get_from.scheme == 'file' then
|
2007-12-20 03:39:12 -05:00
|
|
|
# check if specified URI contains a drive letter (file:/D:/Temp)
|
|
|
|
get_from = get_from.to_s
|
|
|
|
get_from = if get_from =~ /^file:.*[a-z]:/i then
|
|
|
|
get_from[6..-1]
|
|
|
|
else
|
|
|
|
get_from[5..-1]
|
|
|
|
end
|
2007-11-10 02:48:56 -05:00
|
|
|
end
|
|
|
|
|
2007-12-20 03:39:12 -05:00
|
|
|
open File.join(get_from.to_s, "Marshal.#{Gem.marshal_version}.Z"), "rb" do |y|
|
2010-02-21 21:52:35 -05:00
|
|
|
source_index_data = Zlib::Inflate.inflate y.read
|
2007-11-10 02:48:56 -05:00
|
|
|
open File.join(save_to, "Marshal.#{Gem.marshal_version}"), "wb" do |out|
|
2010-02-21 21:52:35 -05:00
|
|
|
out.write source_index_data
|
2007-11-10 02:48:56 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-02-21 21:52:35 -05:00
|
|
|
source_index = Marshal.load source_index_data
|
2007-11-10 02:48:56 -05:00
|
|
|
|
2010-02-21 21:52:35 -05:00
|
|
|
progress = ui.progress_reporter source_index.size,
|
|
|
|
"Fetching #{source_index.size} gems"
|
|
|
|
source_index.each do |fullname, gem|
|
|
|
|
gem_file = gem.file_name
|
2007-11-10 02:48:56 -05:00
|
|
|
gem_dest = File.join gems_dir, gem_file
|
|
|
|
|
|
|
|
unless File.exist? gem_dest then
|
|
|
|
begin
|
|
|
|
open "#{get_from}/gems/#{gem_file}", "rb" do |g|
|
|
|
|
contents = g.read
|
|
|
|
open gem_dest, "wb" do |out|
|
|
|
|
out.write contents
|
|
|
|
end
|
|
|
|
end
|
|
|
|
rescue
|
|
|
|
old_gf = gem_file
|
|
|
|
gem_file = gem_file.downcase
|
|
|
|
retry if old_gf != gem_file
|
|
|
|
alert_error $!
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
progress.updated gem_file
|
|
|
|
end
|
|
|
|
|
|
|
|
progress.done
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|