Class: Razor::CLI::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/razor/cli/command.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parse, navigate, commands, segments) ⇒ Command

Returns a new instance of Command.



2
3
4
5
6
7
# File 'lib/razor/cli/command.rb', line 2

def initialize(parse, navigate, commands, segments)
  @parse = parse
  @navigate = navigate
  @commands = commands
  @segments = segments
end

Class Method Details

.arg_type(arg_name, cmd_schema) ⇒ Object



76
77
78
79
80
81
82
# File 'lib/razor/cli/command.rb', line 76

def self.arg_type(arg_name, cmd_schema)
  # Short-circuit to allow this as a work-around for backwards compatibility.
  return nil if arg_name == 'json'
  return nil unless cmd_schema.is_a?(Hash)
  return cmd_schema[arg_name]['type'] if cmd_schema.has_key?(arg_name)
  return nil
end

.convert_arg(arg_name, value, existing_value, cmd_schema) ⇒ Object

‘cmd_name`: The name of the command being executed. `arg_name`: The name of the argument being formatted. `value`: The original value provided by the user. `existing_value`: The value already assigned to this variable

by previous calls to this method. The new `value` will be
concatenated to an array or hash if an array/hash is
accepted by the command for the given argument.


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
# File 'lib/razor/cli/command.rb', line 91

def self.convert_arg(arg_name, value, existing_value, cmd_schema)
  value = nil if value == "null"

  argument_type = arg_type(arg_name, cmd_schema)

  # This might be helpful, since there's no other method for debug-level logging on the client.
  puts "Formatting argument #{arg_name} with value #{value} as #{argument_type}\n" if @parse && @parse.dump_response?

  case argument_type
    when "array"
      existing_value ||= []
      begin
        existing_value + Array(MultiJson::load(value))
      rescue MultiJson::LoadError => _
        existing_value + Array(value)
      end
    when "object"
      existing_value ||= {}
      begin
        if value =~ /\A(.+?)=(.+)?\z/
          # `--arg name=value`
          existing_value.merge($1 => $2)
        else
          MultiJson::load(value).tap do |value|
            value.is_a?(Hash) or raise ArgumentError, "Invalid object for argument '#{arg_name}'"
            existing_value.merge(value)
          end
        end
      rescue MultiJson::LoadError => error
        raise ArgumentError, "Invalid object for argument '#{arg_name}': #{error.message}"
      end
    when "boolean"
      ["true", nil].include?(value)
    when "number"
      begin
        Integer(value)
      rescue ArgumentError
        raise ArgumentError, "Invalid integer for argument '#{arg_name}': #{value}"
      end
    when "null"
      raise ArgumentError, "Expected nothing for argument '#{arg_name}', but was: '#{value}'" unless value.nil?
      nil
    when "string", nil # `nil` for 'might be an alias, send as-is'
      value
    else
      raise Razor::CLI::Error, "Unexpected datatype '#{argument_type}' for argument #{arg_name}"
  end
end

.resolve_alias(arg_name, cmd_schema) ⇒ Object



140
141
142
143
144
145
146
147
148
149
# File 'lib/razor/cli/command.rb', line 140

def self.resolve_alias(arg_name, cmd_schema)
  return arg_name if cmd_schema[arg_name]
  cmd_schema.find do |other_attr, |
    if  && .has_key?('aliases')
      return other_attr if ['aliases'].find {|aliaz| aliaz == arg_name}
    end
  end
  # No results; return the same name to generate a reasonable error message.
  arg_name
end

Instance Method Details

#cmd_schema(cmd_url) ⇒ Object



68
69
70
71
72
73
74
# File 'lib/razor/cli/command.rb', line 68

def cmd_schema(cmd_url)
  begin
    @navigate.json_get(cmd_url)['schema']
  rescue RestClient::ResourceNotFound => _
    raise VersionCompatibilityError, 'Server must supply the expected datatypes for command arguments; use `--json` or upgrade razor-server'
  end
end

#command(name) ⇒ Object



33
34
35
# File 'lib/razor/cli/command.rb', line 33

def command(name)
  @command ||= @commands.find { |coll| coll["name"] == name }
end

#extract_commandObject



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
# File 'lib/razor/cli/command.rb', line 37

def extract_command
  cmd = command(@segments.shift)
  @cmd_url = URI.parse(cmd['id'])
  @cmd_schema = cmd_schema(@cmd_url)
  body = {}
  until @segments.empty?
    argument = @segments.shift
    if argument =~ /\A--([a-z-]+)(=(.+))?\Z/
      # `--arg=value` or `--arg value`
      arg, value = [$1, $3]
      value = @segments.shift if value.nil? && @segments[0] !~ /^--/
      arg = self.class.resolve_alias(arg, @cmd_schema)
      body[arg] = self.class.convert_arg(arg, value, body[arg], @cmd_schema)
    else
      raise ArgumentError, "Unexpected argument #{argument}"
    end
  end

  begin
    body = MultiJson::load(File::read(body["json"])) if body["json"]
  rescue MultiJson::LoadError
    raise Razor::CLI::Error, "File #{body["json"]} is not valid JSON"
  rescue Errno::ENOENT
    raise Razor::CLI::Error, "File #{body["json"]} not found"
  rescue Errno::EACCES
    raise Razor::CLI::Error,
          "Permission to read file #{body["json"]} denied"
  end
  [cmd, body]
end

#runObject



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/razor/cli/command.rb', line 9

def run
  # @todo lutter 2013-08-16: None of this has any tests, and error
  # handling is heinous at best
  cmd, body = extract_command
  # Ensure that we copy authentication data from our previous URL.
  url = URI.parse(cmd["id"])
  if @doc_resource
    url          = URI.parse(url.to_s)
  end

  if @parse.show_command_help?
    @navigate.json_get(url)
  else
    if body.empty?
      raise Razor::CLI::Error,
            "No arguments for command (did you forget --json ?)"
    end
    result = @navigate.json_post(url, body)
    # Get actual object from the id.
    result = result.merge(@navigate.json_get(URI.parse(result['id']))) if result['id']
    result
  end
end