Module: Hocon::CLI

Defined in:
lib/hocon/cli.rb

Defined Under Namespace

Classes: MissingPathError

Constant Summary collapse

ConfigMissingError =

Aliases

Hocon::ConfigError::ConfigMissingError
ConfigWrongTypeError =
Hocon::ConfigError::ConfigWrongTypeError
SUBCOMMANDS =

List of valid subcommands

['get', 'set', 'unset']

Class Method Summary collapse

Class Method Details

.do_get(opts, hocon_text) ⇒ Object

Entry point for the ‘get’ subcommand Returns a string representation of the the value at the path given on the command line



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/hocon/cli.rb', line 133

def self.do_get(opts, hocon_text)
  config = Hocon::ConfigFactory.parse_string(hocon_text)
  unless config.has_path?(opts[:path])
    raise MissingPathError.new
  end

  value = config.get_any_ref(opts[:path])

  render_options = Hocon::ConfigRenderOptions.defaults
  # Otherwise weird comments show up in the output
  render_options.origin_comments = false
  # If json is false, the hocon format is used
  render_options.json = opts[:json]
  # Output colons between keys and values
  render_options.key_value_separator = :colon

  Hocon::ConfigValueFactory.from_any_ref(value).render(render_options)
end

.do_set(opts, hocon_text) ⇒ Object

Entry point for the ‘set’ subcommand Returns a string representation of the HOCON config after adding/replacing the value at the given path with the given value



155
156
157
158
159
160
# File 'lib/hocon/cli.rb', line 155

def self.do_set(opts, hocon_text)
  config_doc = Hocon::Parser::ConfigDocumentFactory.parse_string(hocon_text)
  modified_config_doc = config_doc.set_value(opts[:path], opts[:new_value])

  modified_config_doc.render
end

.do_unset(opts, hocon_text) ⇒ Object

Entry point for the ‘unset’ subcommand Returns a string representation of the HOCON config after removing the value at the given path



165
166
167
168
169
170
171
172
173
174
# File 'lib/hocon/cli.rb', line 165

def self.do_unset(opts, hocon_text)
  config_doc = Hocon::Parser::ConfigDocumentFactory.parse_string(hocon_text)
  unless config_doc.has_value?(opts[:path])
    raise MissingPathError.new
  end

  modified_config_doc = config_doc.remove_value(opts[:path])

  modified_config_doc.render
end

.exit_with_error(message) ⇒ Object

Print an error message and exit the program



186
187
188
189
# File 'lib/hocon/cli.rb', line 186

def self.exit_with_error(message)
  STDERR.puts "Error: #{message}"
  exit(1)
end

.exit_with_usage_and_error(opt_parser, message) ⇒ Object

Print an error message and usage, then exit the program



192
193
194
195
# File 'lib/hocon/cli.rb', line 192

def self.exit_with_usage_and_error(opt_parser, message)
  STDERR.puts opt_parser
  exit_with_error(message)
end

.get_hocon_file(in_file) ⇒ Object

If a file is provided, return it’s contents. Otherwise read from STDIN



177
178
179
180
181
182
183
# File 'lib/hocon/cli.rb', line 177

def self.get_hocon_file(in_file)
  if in_file
    File.read(in_file)
  else
    STDIN.read
  end
end

.invalid_subcommand_error(subcommand, opt_parser) ⇒ Object

Exits with an error for when a subcommand doesn’t exist. Prints the usage



212
213
214
215
# File 'lib/hocon/cli.rb', line 212

def self.invalid_subcommand_error(subcommand, opt_parser)
  error_message = "Invalid subcommand '#{subcommand}', must be one of [#{SUBCOMMANDS.join(', ')}]"
  exit_with_usage_and_error(opt_parser, error_message)
end

.main(opts) ⇒ Object

Main entry point into the script Calls the appropriate subcommand and handles errors raised from the subcommands



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/hocon/cli.rb', line 110

def self.main(opts)
  hocon_text = get_hocon_file(opts[:in_file])

  begin
    case opts[:subcommand]
      when 'get'
        puts do_get(opts, hocon_text)
      when 'set'
        print_or_write(do_set(opts, hocon_text), opts[:out_file])
      when 'unset'
        print_or_write(do_unset(opts, hocon_text), opts[:out_file])
    end

  rescue MissingPathError
    exit_with_error("Can't find the given path: '#{opts[:path]}'")
  end

  exit
end

.no_subcommand_error(opt_parser) ⇒ Object

Exits with an error for when no subcommand is supplied on the command line. Prints the usage



206
207
208
209
# File 'lib/hocon/cli.rb', line 206

def self.no_subcommand_error(opt_parser)
  error_message = "Must specify subcommand from [#{SUBCOMMANDS.join(', ')}]"
  exit_with_usage_and_error(opt_parser, error_message)
end

.parse_args(args) ⇒ Object

Parses the command line flags and argument Returns a options hash with values for each option and argument



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
# File 'lib/hocon/cli.rb', line 24

def self.parse_args(args)
  options = {}
  opt_parser = OptionParser.new do |opts|
    subcommands = SUBCOMMANDS.join(',')
    opts.banner = "Usage: hocon [options] {#{subcommands}} PATH [VALUE]\n\n" +
        "Example usages:\n" +
        "  hocon -i settings.conf -o new_settings.conf set some.nested.value 42\n" +
        "  hocon -f settings.conf set some.nested.value 42\n" +
        "  cat settings.conf | hocon get some.nested.value\n\n" +
        "Subcommands:\n" +
        "  get PATH - Returns the value at the given path\n" +
        "  set PATH VALUE - Sets or adds the given value at the given path\n" +
        "  unset PATH - Removes the value at the given path"

    opts.separator('')
    opts.separator('Options:')

    in_file_description = 'HOCON file to read/modify. If omitted, STDIN assumed'
    opts.on('-i', '--in-file HOCON_FILE', in_file_description) do |in_file|
      options[:in_file] = in_file
    end

    out_file_description = 'File to be written to. If omitted, STDOUT assumed'
    opts.on('-o', '--out-file HOCON_FILE', out_file_description) do |out_file|
      options[:out_file] = out_file
    end

    file_description = 'File to read/write to. Equivalent to setting -i/-o to the same file'
    opts.on('-f', '--file HOCON_FILE', file_description) do |file|
      options[:file] = file
    end

    json_description = "Output values from the 'get' subcommand in json format"
    opts.on('-j', '--json', json_description) do |json|
      options[:json] = json
    end

    opts.on_tail('-h', '--help', 'Show this message') do
      puts opts
      exit
    end

    opts.on_tail('-v', '--version', 'Show version') do
      puts Hocon::Version::STRING
      exit
    end
  end
  # parse! returns the argument list minus all the flags it found
  remaining_args = opt_parser.parse!(args)

  # Ensure -i and -o aren't used at the same time as -f
  if (options[:in_file] || options[:out_file]) && options[:file]
    exit_with_usage_and_error(opt_parser, "--file can't be used with --in-file or --out-file")
  end

  # If --file is used, set --in/out-file to the same file
  if options[:file]
    options[:in_file] = options[:file]
    options[:out_file] = options[:file]
  end

  no_subcommand_error(opt_parser) unless remaining_args.size > 0

  # Assume the first arg is the subcommand
  subcommand = remaining_args.shift
  options[:subcommand] = subcommand

  case subcommand
    when 'set'
      subcommand_arguments_error(subcommand, opt_parser) unless remaining_args.size >= 2
      options[:path] = remaining_args.shift
      options[:new_value] = remaining_args.shift

    when 'get', 'unset'
      subcommand_arguments_error(subcommand, opt_parser) unless remaining_args.size >= 1
      options[:path] = remaining_args.shift

    else
      invalid_subcommand_error(subcommand, opt_parser)
  end

  options
end

If out_file is not nil, write to that file. Otherwise print to STDOUT



218
219
220
221
222
223
224
# File 'lib/hocon/cli.rb', line 218

def self.print_or_write(string, out_file)
  if out_file
    File.open(out_file, 'w') { |file| file.write(string) }
  else
    puts string
  end
end

.subcommand_arguments_error(subcommand, opt_parser) ⇒ Object

Exits with an error saying there aren’t enough arguments found for a given subcommand. Prints the usage



199
200
201
202
# File 'lib/hocon/cli.rb', line 199

def self.subcommand_arguments_error(subcommand, opt_parser)
  error_message = "Too few arguments for '#{subcommand}' subcommand"
  exit_with_usage_and_error(opt_parser, error_message)
end