class Razor::CLI::Navigate

Constants

RAZOR_HTTPS_API
RAZOR_HTTP_API

Attributes

doc_resource[RW]

Public Class Methods

new(parse, segments) click to toggle source
# File lib/razor/cli/navigate.rb, line 12
def initialize(parse, segments)
  @parse = parse
  @segments = segments||[]
  set_api_url!(parse)
  @doc = entrypoint
  @doc_resource = create_resource parse.api_url, default_headers
end

Public Instance Methods

accept_language() click to toggle source
# File lib/razor/cli/navigate.rb, line 143
def accept_language
  @accept_language ||= GettextSetup.candidate_locales
end
collections() click to toggle source
# File lib/razor/cli/navigate.rb, line 60
def collections
  entrypoint["collections"]
end
command(name) click to toggle source
# File lib/razor/cli/navigate.rb, line 76
def command(name)
  @command ||= commands.find { |coll| coll["name"] == name }
end
command?() click to toggle source
# File lib/razor/cli/navigate.rb, line 80
def command?
  !! command(@segments.first)
end
commands() click to toggle source
# File lib/razor/cli/navigate.rb, line 64
def commands
  entrypoint["commands"]
end
default_api() click to toggle source

This returns an array of two elements:

  • The URL that, if neither the `-u` argument nor the RAZOR_API environment variable are set, will be used.

  • The source from which the URL was found, `:https` or `:http`.

# File lib/razor/cli/navigate.rb, line 24
def default_api
  if https_api_exists?
    [RAZOR_HTTPS_API, :https]
  else
    [RAZOR_HTTP_API, :http]
  end
end
default_headers() click to toggle source
# File lib/razor/cli/navigate.rb, line 147
def default_headers
  {'accept' => 'application/json',
   'accept_language' => accept_language}
end
entrypoint() click to toggle source
# File lib/razor/cli/navigate.rb, line 56
def entrypoint
  @entrypoint ||= json_get(@parse.api_url)
end
get(url, headers={}) click to toggle source
# File lib/razor/cli/navigate.rb, line 159
def get(url, headers={})
  resource = create_resource(url, headers)
  response = resource.get
  print "GET #{url.to_s}\n#{response.body}\n\n" if @parse.dump_response?
  response
end
get_document() click to toggle source
# File lib/razor/cli/navigate.rb, line 86
def get_document
  if @segments.empty?
    entrypoint
  elsif query?
    Razor::CLI::Query.new(@parse, self, collections, @segments).run
  elsif command?
    cmd = @segments.shift
    command = commands.find { |coll| coll["name"] == cmd }
    cmd_url = URI.parse(command['id'])
    # Ensure that we copy authentication data from our previous URL.
    if @doc_resource
      cmd_url = URI.parse(cmd_url.to_s)
    end
    command = json_get(cmd_url)
    Razor::CLI::Command.new(@parse, self, command, @segments, cmd_url).run
  else
    raise NavigationError.new(@doc_resource.build_url, @segments, @doc)
  end
end
head(url, headers={}) click to toggle source
# File lib/razor/cli/navigate.rb, line 152
def head(url, headers={})
  resource = create_resource(url, headers)
  response = resource.head
  print "HEAD #{url.to_s}\n#{response.body}\n\n" if @parse.dump_response?
  response
end
json_get(url, headers = {}, params = {}) click to toggle source
# File lib/razor/cli/navigate.rb, line 166
def json_get(url, headers = {}, params = {})
  # Add extra parameters to URL.
  url.query = URI.encode_www_form(params)
  url.query = nil if url.query.empty? # Remove dangling '?' from URL.
  @username ||= url.user
  @password ||= url.password

  response = get(url, headers.merge(default_headers))
  if response.status == 401
    raise UnauthorizedError.new(url)
  end
  unless response.headers[:content_type] =~ /application\/json/
    raise _('Received content type %{content_type}') % {content_type: response.headers[:content_type]}
  end
  MultiJson.load(response.body)
end
json_post(url, body) click to toggle source
# File lib/razor/cli/navigate.rb, line 183
def json_post(url, body)
  @username ||= url.user
  @password ||= url.password

  headers = {'Content-Type' => 'application/json'}.merge(default_headers)
  begin
    resource = create_resource(url, headers)
    # `nil` here because the URL above is absolute, not relative.
    response = resource.post nil, MultiJson::dump(body)
    if response.status == 401
      raise UnauthorizedError.new(url)
    end
  ensure
    if @parse.dump_response?
      print "POST #{url.to_s}\n#{body}\n-->\n"
      puts (response ? response.body : _("ERROR"))
    end
  end
  MultiJson::load(response.body)
end
last_url() click to toggle source
# File lib/razor/cli/navigate.rb, line 52
def last_url
  @doc_resource.build_url
end
move_to(key, doc = @doc, params = {}) click to toggle source
# File lib/razor/cli/navigate.rb, line 106
def move_to(key, doc = @doc, params = {})
  @doc = doc
  if @doc.is_a? Array
    obj = @doc.find {|x| x.is_a?(Hash) and x["name"] == key }
  elsif @doc.is_a?(Hash) && @doc['items'].is_a?(Array)
    obj = @doc['items'].find {|x| x.is_a?(Hash) and x["name"] == key }
  elsif @doc.is_a?(Hash)
    obj = @doc[key]
  end

  raise NavigationError.new(@doc_resource.build_url, key, @doc) if obj.nil?

  if obj.is_a?(Hash) && obj["id"]
    url = URI.parse(obj["id"])

    @doc = json_get(url, {}, params)
  elsif obj.is_a?(Hash) && obj['spec']
    @doc = obj
  elsif obj.is_a?(Hash) || obj.is_a?(Array)
    # We have reached a data structure that doesn't have a spec string!
    # This means we should use the parent's string and keep track of which
    # extra navigation is needed, so we can still format the data
    # accordingly.
    if @doc['+spec'].is_a?(Array)
      # Something's been added.
      @doc['+spec'] << key
    elsif @doc['+spec'].nil? || @doc['+spec'].is_a?(String)
      @doc['+spec'] = [@doc['spec'], key]
    end
    @doc = obj.merge({'+spec' => @doc['+spec']}) if obj.is_a?(Hash)
    @doc = {'+spec' => @doc['+spec'], 'items' => obj} if obj.is_a?(Array)
    @doc
  else
    @doc = obj
  end
end
query?() click to toggle source
# File lib/razor/cli/navigate.rb, line 72
def query?
  @query ||= collections.any? { |coll| coll["name"] == @segments.first }
end
server_version() click to toggle source
# File lib/razor/cli/navigate.rb, line 68
def server_version
  entrypoint.has_key?('version') and entrypoint['version']['server'] or _('Unknown')
end
set_api_url!(parse) click to toggle source

The order of API selection works as follows:

  • Use `-u` argument if defined (done elsewhere)

  • Use “RAZOR_API” environment variable if defined

  • Check PE's localhost:8151/api via `HEAD` HTTP method

  • Use FOSS' localhost:8150/api

This receives an argument determining whether to be verbose about requests made.

# File lib/razor/cli/navigate.rb, line 39
def set_api_url!(parse)
  if !!parse.api_url
    parse.api_url.to_s
  elsif ENV["RAZOR_API"]
    parse.parse_and_set_api_url(ENV['RAZOR_API'], :env)
  else
    url, source = default_api
    parse.parse_and_set_api_url(url, source)
  end
end

Private Instance Methods

create_resource(url, headers) click to toggle source
# File lib/razor/cli/navigate.rb, line 220
def create_resource(url, headers)
  @doc_resource = Faraday.new(url,
      :headers => headers,
      :ssl => {verify: @parse.verify_ssl?,
               ca_file: @parse.ssl_ca_file}).tap do |req|
        # Add these in case the URL above doesn't include authentication.
        req.basic_auth(@username || url.user, @password || url.password)
  end
end
https_api_exists?() click to toggle source
# File lib/razor/cli/navigate.rb, line 205
def https_api_exists?
  # No need to verify SSL on localhost, cert won't match.
  old_verify_ssl = @parse.verify_ssl?
  @parse.verify_ssl = false
  begin
    url = RAZOR_HTTPS_API
    head(URI.parse(url))
  rescue Errno::ENOENT, Faraday::ConnectionFailed
    false
  ensure
    print "HEAD #{url.to_s}\n\n" if @parse.dump_response?
    @parse.verify_ssl = old_verify_ssl
  end
end