summaryrefslogtreecommitdiff
path: root/lib/rubygems/commands/sources_command.rb
blob: 245ab91c9f7192ca1943ed5649f48907b2093df9 (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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
require 'fileutils'
require 'rubygems/command'
require 'rubygems/remote_fetcher'
require 'rubygems/source_info_cache'
require 'rubygems/spec_fetcher'
require 'rubygems/local_remote_options'

class Gem::Commands::SourcesCommand < Gem::Command

  include Gem::LocalRemoteOptions

  def initialize
    super 'sources',
          'Manage the sources and cache file RubyGems uses to search for gems'

    add_option '-a', '--add SOURCE_URI', 'Add source' do |value, options|
      options[:add] = value
    end

    add_option '-l', '--list', 'List sources' do |value, options|
      options[:list] = value
    end

    add_option '-r', '--remove SOURCE_URI', 'Remove source' do |value, options|
      options[:remove] = value
    end

    add_option '-c', '--clear-all',
               'Remove all sources (clear the cache)' do |value, options|
      options[:clear_all] = value
    end

    add_option '-u', '--update', 'Update source cache' do |value, options|
      options[:update] = value
    end

    add_proxy_option
  end

  def defaults_str
    '--list'
  end

  def execute
    options[:list] = !(options[:add] ||
                       options[:clear_all] ||
                       options[:remove] ||
                       options[:update])

    if options[:clear_all] then
      path = Gem::SpecFetcher.fetcher.dir
      FileUtils.rm_rf path

      if not File.exist?(path) then
        say "*** Removed specs cache ***"
      elsif not File.writable?(path) then
        say "*** Unable to remove source cache (write protected) ***"
      else
        say "*** Unable to remove source cache ***"
      end

      sic = Gem::SourceInfoCache
      remove_cache_file 'user',          sic.user_cache_file
      remove_cache_file 'latest user',   sic.latest_user_cache_file
      remove_cache_file 'system',        sic.system_cache_file
      remove_cache_file 'latest system', sic.latest_system_cache_file
    end

    if options[:add] then
      source_uri = options[:add]
      uri = URI.parse source_uri

      begin
        Gem::SpecFetcher.fetcher.load_specs uri, 'specs'
        Gem.sources << source_uri
        Gem.configuration.write

        say "#{source_uri} added to sources"
      rescue URI::Error, ArgumentError
        say "#{source_uri} is not a URI"
      rescue Gem::RemoteFetcher::FetchError => e
        yaml_uri = uri + 'yaml'
        gem_repo = Gem::RemoteFetcher.fetcher.fetch_size yaml_uri rescue false

        if e.uri =~ /specs\.#{Regexp.escape Gem.marshal_version}\.gz$/ and
           gem_repo then

          alert_warning <<-EOF
RubyGems 1.2+ index not found for:
\t#{source_uri}

Will cause RubyGems to revert to legacy indexes, degrading performance.
          EOF

          say "#{source_uri} added to sources"
        else
          say "Error fetching #{source_uri}:\n\t#{e.message}"
        end
      end
    end

    if options[:remove] then
      source_uri = options[:remove]

      unless Gem.sources.include? source_uri then
        say "source #{source_uri} not present in cache"
      else
        Gem.sources.delete source_uri
        Gem.configuration.write

        say "#{source_uri} removed from sources"
      end
    end

    if options[:update] then
      fetcher = Gem::SpecFetcher.fetcher

      if fetcher.legacy_repos.empty? then
        Gem.sources.each do |update_uri|
          update_uri = URI.parse update_uri
          fetcher.load_specs update_uri, 'specs'
          fetcher.load_specs update_uri, 'latest_specs'
        end
      else
        Gem::SourceInfoCache.cache true
        Gem::SourceInfoCache.cache.flush
      end

      say "source cache successfully updated"
    end

    if options[:list] then
      say "*** CURRENT SOURCES ***"
      say

      Gem.sources.each do |source|
        say source
      end
    end
  end

  private

  def remove_cache_file(desc, path)
    FileUtils.rm_rf path

    if not File.exist?(path) then
      say "*** Removed #{desc} source cache ***"
    elsif not File.writable?(path) then
      say "*** Unable to remove #{desc} source cache (write protected) ***"
    else
      say "*** Unable to remove #{desc} source cache ***"
    end
  end

end