1# frozen_string_literal: true
2require "rubygems/deprecate"
3
4##
5# Available list of platforms for targeting Gem installations.
6#
7# See `gem help platform` for information on platform matching.
8
9class Gem::Platform
10
11  @local = nil
12
13  attr_accessor :cpu
14
15  attr_accessor :os
16
17  attr_accessor :version
18
19  def self.local
20    arch = RbConfig::CONFIG['arch']
21    arch = "#{arch}_60" if arch =~ /mswin(?:32|64)$/
22    @local ||= new(arch)
23  end
24
25  def self.match(platform)
26    Gem.platforms.any? do |local_platform|
27      platform.nil? or
28        local_platform == platform or
29        (local_platform != Gem::Platform::RUBY and local_platform =~ platform)
30    end
31  end
32
33  def self.installable?(spec)
34    if spec.respond_to? :installable_platform?
35      spec.installable_platform?
36    else
37      match spec.platform
38    end
39  end
40
41  def self.new(arch) # :nodoc:
42    case arch
43    when Gem::Platform::CURRENT then
44      Gem::Platform.local
45    when Gem::Platform::RUBY, nil, '' then
46      Gem::Platform::RUBY
47    else
48      super
49    end
50  end
51
52  def initialize(arch)
53    case arch
54    when Array then
55      @cpu, @os, @version = arch
56    when String then
57      arch = arch.split '-'
58
59      if arch.length > 2 and arch.last !~ /\d/  # reassemble x86-linux-gnu
60        extra = arch.pop
61        arch.last << "-#{extra}"
62      end
63
64      cpu = arch.shift
65
66      @cpu = case cpu
67             when /i\d86/ then 'x86'
68             else cpu
69             end
70
71      if arch.length == 2 and arch.last =~ /^\d+(\.\d+)?$/  # for command-line
72        @os, @version = arch
73        return
74      end
75
76      os, = arch
77      @cpu, os = nil, cpu if os.nil? # legacy jruby
78
79      @os, @version = case os
80                      when /aix(\d+)?/ then             [ 'aix',       $1  ]
81                      when /cygwin/ then                [ 'cygwin',    nil ]
82                      when /darwin(\d+)?/ then          [ 'darwin',    $1  ]
83                      when /^macruby$/ then             [ 'macruby',   nil ]
84                      when /freebsd(\d+)?/ then         [ 'freebsd',   $1  ]
85                      when /hpux(\d+)?/ then            [ 'hpux',      $1  ]
86                      when /^java$/, /^jruby$/ then     [ 'java',      nil ]
87                      when /^java([\d.]*)/ then         [ 'java',      $1  ]
88                      when /^dalvik(\d+)?$/ then        [ 'dalvik',    $1  ]
89                      when /^dotnet$/ then              [ 'dotnet',    nil ]
90                      when /^dotnet([\d.]*)/ then       [ 'dotnet',    $1  ]
91                      when /linux/ then                 [ 'linux',     $1  ]
92                      when /mingw32/ then               [ 'mingw32',   nil ]
93                      when /(mswin\d+)(\_(\d+))?/ then
94                        os, version = $1, $3
95                        @cpu = 'x86' if @cpu.nil? and os =~ /32$/
96                        [os, version]
97                      when /netbsdelf/ then             [ 'netbsdelf', nil ]
98                      when /openbsd(\d+\.\d+)?/ then    [ 'openbsd',   $1  ]
99                      when /bitrig(\d+\.\d+)?/ then     [ 'bitrig',    $1  ]
100                      when /solaris(\d+\.\d+)?/ then    [ 'solaris',   $1  ]
101                      # test
102                      when /^(\w+_platform)(\d+)?/ then [ $1,          $2  ]
103                      else                              [ 'unknown',   nil ]
104                      end
105    when Gem::Platform then
106      @cpu = arch.cpu
107      @os = arch.os
108      @version = arch.version
109    else
110      raise ArgumentError, "invalid argument #{arch.inspect}"
111    end
112  end
113
114  def inspect
115    "%s @cpu=%p, @os=%p, @version=%p>" % [super[0..-2], *to_a]
116  end
117
118  def to_a
119    [@cpu, @os, @version]
120  end
121
122  def to_s
123    to_a.compact.join '-'
124  end
125
126  ##
127  # Is +other+ equal to this platform?  Two platforms are equal if they have
128  # the same CPU, OS and version.
129
130  def ==(other)
131    self.class === other and to_a == other.to_a
132  end
133
134  alias :eql? :==
135
136  def hash # :nodoc:
137    to_a.hash
138  end
139
140  ##
141  # Does +other+ match this platform?  Two platforms match if they have the
142  # same CPU, or either has a CPU of 'universal', they have the same OS, and
143  # they have the same version, or either has no version.
144  #
145  # Additionally, the platform will match if the local CPU is 'arm' and the
146  # other CPU starts with "arm" (for generic ARM family support).
147
148  def ===(other)
149    return nil unless Gem::Platform === other
150
151    # cpu
152    ([nil,'universal'].include?(@cpu) or [nil, 'universal'].include?(other.cpu) or @cpu == other.cpu or
153    (@cpu == 'arm' and other.cpu =~ /\Aarm/)) and
154
155    # os
156    @os == other.os and
157
158    # version
159    (@version.nil? or other.version.nil? or @version == other.version)
160  end
161
162  ##
163  # Does +other+ match this platform?  If +other+ is a String it will be
164  # converted to a Gem::Platform first.  See #=== for matching rules.
165
166  def =~(other)
167    case other
168    when Gem::Platform then # nop
169    when String then
170      # This data is from http://gems.rubyforge.org/gems/yaml on 19 Aug 2007
171      other = case other
172              when /^i686-darwin(\d)/     then ['x86',       'darwin',  $1    ]
173              when /^i\d86-linux/         then ['x86',       'linux',   nil   ]
174              when 'java', 'jruby'        then [nil,         'java',    nil   ]
175              when /^dalvik(\d+)?$/       then [nil,         'dalvik',  $1    ]
176              when /dotnet(\-(\d+\.\d+))?/ then ['universal','dotnet',  $2    ]
177              when /mswin32(\_(\d+))?/    then ['x86',       'mswin32', $2    ]
178              when /mswin64(\_(\d+))?/    then ['x64',       'mswin64', $2    ]
179              when 'powerpc-darwin'       then ['powerpc',   'darwin',  nil   ]
180              when /powerpc-darwin(\d)/   then ['powerpc',   'darwin',  $1    ]
181              when /sparc-solaris2.8/     then ['sparc',     'solaris', '2.8' ]
182              when /universal-darwin(\d)/ then ['universal', 'darwin',  $1    ]
183              else                             other
184              end
185
186      other = Gem::Platform.new other
187    else
188      return nil
189    end
190
191    self === other
192  end
193
194  ##
195  # A pure-Ruby gem that may use Gem::Specification#extensions to build
196  # binary files.
197
198  RUBY = 'ruby'.freeze
199
200  ##
201  # A platform-specific gem that is built for the packaging Ruby's platform.
202  # This will be replaced with Gem::Platform::local.
203
204  CURRENT = 'current'.freeze
205end
206