Class: Gem::SpecificationPolicy

Inherits:
Object
  • Object
show all
Includes:
UserInteraction
Defined in:
lib/rubygems/specification_policy.rb

Constant Summary collapse

VALID_NAME_PATTERN =

:nodoc:

/\A[a-zA-Z0-9\.\-\_]+\z/.freeze
SPECIAL_CHARACTERS =

:nodoc:

/\A[#{Regexp.escape('.-_')}]+/.freeze
VALID_URI_PATTERN =

:nodoc:

%r{\Ahttps?:\/\/([^\s:@]+:[^\s:@]*@)?[A-Za-z\d\-]+(\.[A-Za-z\d\-]+)+\.?(:\d{1,5})?([\/?]\S*)?\z}.freeze
%w[
  bug_tracker_uri
  changelog_uri
  documentation_uri
  homepage_uri
  mailing_list_uri
  source_code_uri
  wiki_uri
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from UserInteraction

#alert, #alert_error, #alert_warning, #ask, #ask_for_password, #ask_yes_no, #choose_from_list, #say, #terminate_interaction, #verbose

Methods included from DefaultUserInteraction

ui, #ui, #ui=, ui=, use_ui, #use_ui

Methods included from Text

#clean_text, #format_text, #levenshtein_distance, #min3, #truncate_text

Constructor Details

#initialize(specification) ⇒ SpecificationPolicy

:nodoc:


23
24
25
26
27
# File 'lib/rubygems/specification_policy.rb', line 23

def initialize(specification)
  @warnings = 0

  @specification = specification
end

Instance Attribute Details

#packagingObject

If set to true, run packaging-specific checks, as well.


32
33
34
# File 'lib/rubygems/specification_policy.rb', line 32

def packaging
  @packaging
end

Instance Method Details

#validate(strict = false) ⇒ Object

Checks that the specification contains all required fields, and does a very basic sanity check.

Raises InvalidSpecificationException if the spec does not pass the checks.


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
# File 'lib/rubygems/specification_policy.rb', line 41

def validate(strict = false)
  validate_nil_attributes

  validate_rubygems_version

  validate_required_attributes

  validate_name

  validate_require_paths

  @specification.keep_only_files_and_directories

  validate_non_files

  validate_self_inclusion_in_files_list

  validate_specification_version

  validate_platform

  validate_array_attributes

  validate_authors_field

  

  validate_licenses

  validate_permissions

  

  validate_values

  validate_dependencies

  if @warnings > 0
    if strict
      error "specification has warnings"
    else
      alert_warning help_text
    end
  end

  true
end

#validate_dependenciesObject

Implementation for Specification#validate_dependencies


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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/rubygems/specification_policy.rb', line 127

def validate_dependencies # :nodoc:
  # NOTE: see REFACTOR note in Gem::Dependency about types - this might be brittle
  seen = Gem::Dependency::TYPES.inject({}) { |types, type| types.merge({ type => {}}) }

  error_messages = []
  warning_messages = []
  @specification.dependencies.each do |dep|
    if prev = seen[dep.type][dep.name]
      error_messages << <<-MESSAGE
duplicate dependency on #{dep}, (#{prev.requirement}) use:
  add_#{dep.type}_dependency '#{dep.name}', '#{dep.requirement}', '#{prev.requirement}'
      MESSAGE
    end

    seen[dep.type][dep.name] = dep

    prerelease_dep = dep.requirements_list.any? do |req|
      Gem::Requirement.new(req).prerelease?
    end

    warning_messages << "prerelease dependency on #{dep} is not recommended" if
        prerelease_dep && !@specification.version.prerelease?

    open_ended = dep.requirement.requirements.all? do |op, version|
      not version.prerelease? and (op == '>' or op == '>=')
    end

    if open_ended
      op, dep_version = dep.requirement.requirements.first

      segments = dep_version.segments

      base = segments.first 2

      recommendation = if (op == '>' || op == '>=') && segments == [0]
                         "  use a bounded requirement, such as '~> x.y'"
                       else
                         bugfix = if op == '>'
                                    ", '> #{dep_version}'"
                                  elsif op == '>=' and base != segments
                                    ", '>= #{dep_version}'"
                                  end

                         "  if #{dep.name} is semantically versioned, use:\n" \
                         "    add_#{dep.type}_dependency '#{dep.name}', '~> #{base.join '.'}'#{bugfix}"
                       end

      warning_messages << ["open-ended dependency on #{dep} is not recommended", recommendation].join("\n") + "\n"
    end
  end
  if error_messages.any?
    error error_messages.join
  end
  if warning_messages.any?
    warning_messages.each { |warning_message| warning warning_message }
  end
end

#validate_metadataObject

Implementation for Specification#validate_metadata


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
# File 'lib/rubygems/specification_policy.rb', line 92

def 
   = @specification.

  unless Hash === 
    error 'metadata must be a hash'
  end

  .each do |key, value|
    if !key.kind_of?(String)
      error "metadata keys must be a String"
    end

    if key.size > 128
      error "metadata key too large (#{key.size} > 128)"
    end

    if !value.kind_of?(String)
      error "metadata values must be a String"
    end

    if value.size > 1024
      error "metadata value too large (#{value.size} > 1024)"
    end

    if METADATA_LINK_KEYS.include? key
      if value !~ VALID_URI_PATTERN
        error "metadata['#{key}'] has invalid link: #{value.inspect}"
      end
    end
  end
end

#validate_permissionsObject

Issues a warning for each file to be packaged which is world-readable.

Implementation for Specification#validate_permissions


190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/rubygems/specification_policy.rb', line 190

def validate_permissions
  return if Gem.win_platform?

  @specification.files.each do |file|
    next unless File.file?(file)
    next if File.stat(file).mode & 0444 == 0444
    warning "#{file} is not world-readable"
  end

  @specification.executables.each do |name|
    exec = File.join @specification.bindir, name
    next unless File.file?(exec)
    next if File.stat(exec).executable?
    warning "#{exec} is not executable"
  end
end