Module: Xolo::Admin::CommandLine

Defined in:
lib/xolo/admin/command_line.rb

Overview

Module for parsing and validating the xadm options from the commandline

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(includer) ⇒ Object

when this module is included



21
22
23
# File 'lib/xolo/admin/command_line.rb', line 21

def self.included(includer)
  Xolo.verbose_include includer, self
end

Instance Method Details

#add_command?Boolean

Returns does the command we’re running add a title or version to xolo?.

Returns:

  • (Boolean)

    does the command we’re running add a title or version to xolo?



431
432
433
# File 'lib/xolo/admin/command_line.rb', line 431

def add_command?
  Xolo::Admin::Options::ADD_COMMANDS.include? cli_cmd.command
end

#edit_command?Boolean

Returns does the command we’re running add a title or version to xolo?.

Returns:

  • (Boolean)

    does the command we’re running add a title or version to xolo?



437
438
439
# File 'lib/xolo/admin/command_line.rb', line 437

def edit_command?
  Xolo::Admin::Options::EDIT_COMMANDS.include? cli_cmd.command
end

#no_target_command?Boolean

Returns does the command we’re running not deal with titles or versions? e.g. ‘config’ or ‘help’.

Returns:

  • (Boolean)

    does the command we’re running not deal with titles or versions? e.g. ‘config’ or ‘help’



425
426
427
# File 'lib/xolo/admin/command_line.rb', line 425

def no_target_command?
  !Xolo::Admin::Options::COMMANDS[cli_cmd.command][:target]
end

#parse_cliObject

Parse ARGV.

First we use Optimist to parse the global opts and populate the OpenStruct Xolo::Admin::Options.global_opts

Then we look at the next arguments on the command line (things without a - or – ) and populate the OpenStruct Xolo::Admin::Options.cli_cmd

Then we use Optimist again to look at any remaining options, which apply to the command, and populate the OpenStruct Xolo::Admin::Options.cli_cmd_opts



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/xolo/admin/command_line.rb', line 43

def parse_cli
  # if we ask for help at all, we never do walkthru
  if ARGV.include?(Xolo::Admin::Options::HELP_OPT) || ARGV.include?(Xolo::Admin::Options::HELP_CMD)
    ARGV.delete '-w'
    ARGV.delete '--walkthru'
  end

  # save the global opts hash from optimist into our OpenStruct
  parse_global_cli.each { |k, v| global_opts[k] = v }

  # Now parse the rest of the command line, getting the
  # command its its args into cli_cmd, and the opts for them
  # into cli_cmd_opts
  parse_command_cli
end

#parse_cmd_and_argsObject

Get the xadm command, and its args (title, maybe version, etc) from the Command Line. They get stored in the cli_cmd OpenStruct.

We don’t use optimist for this, we just examine the first items of ARGV until we hit one starting with a dash.



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/xolo/admin/command_line.rb', line 212

def parse_cmd_and_args
  # next item will be the command we are executing
  cli_cmd.command = ARGV.shift

  # if there is no command, treat it like `xadm --help`
  return if reparse_global_cli_for_help?

  # we have a command, validate it
  validate_cli_command

  # Some commands, like 'config', always do walkthru
  global_opts.walkthru = true if cli_cmd.command == Xolo::Admin::Options::CONFIG_CMD

  # if the command is 'help'
  # then
  #   'xadm [globalOpts] help' becomes 'xadm --help'
  # and
  #   'xadm [globalOpts] help command' becomes 'xadm [globalOpts] command --help'
  #
  # in those forms, Optimist will deal with displaying the help.
  #
  if cli_cmd.command == Xolo::Admin::Options::HELP_CMD

    # 'xadm [globalOpts] help' becomes 'xadm --help' (via the reparse method)
    cli_cmd.command = ARGV.shift
    return if reparse_global_cli_for_help?

    # we have a new command, for which we are getting help. Validate it
    validate_cli_command

    # 'xadm [globalOpts] help command' becomes 'xadm [globalOpts] command --help'
    ARGV.unshift Xolo::Admin::Options::HELP_OPT
  end
  # if we are here and any part of ARGV is --help, nothing more to do.
  return if ARGV.include?(Xolo::Admin::Options::HELP_OPT)

  # if we are saving the client code, we don't need to log in
  return if cli_cmd.command == Xolo::Admin::Options::SAVE_CLIENT_CODE_CMD

  # log in now, cuz we need the server to validate the rest of the
  # command line
  #
  # TODO: Be pickier about which commands actually need the server, and
  # only log in for them.
  #################
  

  # What kind of command do we have, since we know it isn't 'help' if we
  # are here.
  if title_command?
    # the next item is the title
    cli_cmd.title = ARGV.shift
    validate_cli_title

  elsif version_command?
    # the next item is the title and the one after that might be a version
    cli_cmd.title = ARGV.shift
    validate_cli_title

    cli_cmd.version = ARGV.shift
    validate_cli_version

  elsif title_or_version_command?
    # the next item is the title and the one after that might be a version
    cli_cmd.title = ARGV.shift
    validate_cli_title

    cli_cmd.version = ARGV.shift unless ARGV.first.to_s.start_with? Xolo::DASH
    validate_cli_version if cli_cmd.version

  end # if
end

#parse_cmd_optsHash

Parse the options for the command. This returns a hash from Optimist

Returns:

  • (Hash)

    the optimist hash



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
# File 'lib/xolo/admin/command_line.rb', line 318

def parse_cmd_opts
  cmd = cli_cmd.command
  return if cmd == Xolo::Admin::Options::HELP_CMD || cmd.to_s.empty?

  # set these for use inside the optimist options block
  ###
  executable_file = Xolo::Admin::EXECUTABLE_FILENAME
  cmd_desc = Xolo::Admin::Options::COMMANDS.dig cmd, :desc
  cmd_long_desc = Xolo::Admin::Options::COMMANDS.dig cmd, :long_desc
  cmd_long_desc &&= format_multiline_indent(cmd_long_desc, indent: 2)
  cmd_usage = Xolo::Admin::Options::COMMANDS.dig cmd, :usage
  cmd_display = Xolo::Admin::Options::COMMANDS.dig cmd, :display
  cmd_opts = Xolo::Admin::Options::COMMANDS.dig cmd, :opts

  title_command?
  vers_cmd = version_command?
  title_or_vers_command = title_or_version_command?
  add_command = add_command?
  edit_command = edit_command?
  arg_banner = Xolo::Admin::Options::COMMANDS.dig(cmd, :arg_banner)
  arg_banner ||= Xolo::Admin::Options::DFT_CMD_TITLE_ARG_BANNER

  # The optimist parser and help generator
  # for the command options
  Optimist.options do
    # NOTE: extra newlines are added to the front of strings, cuz
    # optimist's 'banner' method chomps the ends.
    banner 'Command:'
    banner "  #{cmd}, #{cmd_desc}"
    if cmd_long_desc
      banner "\nDescription:"
      banner "  #{cmd_long_desc}"
    end

    banner "\nUsage:"
    usage = cmd_usage || "#{executable_file} [global options] #{cmd_display} [options]"
    banner "  #{usage}"

    unless arg_banner == :none
      banner "\nArguments:"
      banner arg_banner
      banner Xolo::Admin::Options::DFT_CMD_VERSION_ARG_BANNER if vers_cmd || title_or_vers_command
    end

    if cmd_opts
      banner "\nOptions:"

      # add a blank line between each of the cli options
      # NOTE: chrisl added this to the optimist.rb included in this project.
      insert_blanks

      # create the optimist options for the command
      cmd_opts.each do |opt_key, deets|
        next unless deets[:cli]

        desc = deets[:desc]

        # Required opts are only required when adding.
        # when editing, they should already exist
        if add_command
          if deets[:edit_only]
            next
          elsif deets[:required]
            desc = "#{desc}REQUIRED"
            required = true
          elsif deets[:title_type]
            desc = "#{desc}Only used with #{deets[:title_type]} titles."
            required = deets[:required]
          else
            required = false
          end
        end

        next if edit_command && deets[:add_only]

        # booleans are CLI flags defaulting to false
        # everything else is a string that we will convert as we validate later
        type = deets[:type] == :boolean ? :boolean : :string

        # here we actually set the optimist opt.
        opt opt_key, desc, short: deets[:cli], type: type, required: required, multi: deets[:multi]
      end # opts_to_use.each
    end # if cmd_opts
  end # Optimist.options
end

#parse_command_clivoid

This method returns an undefined value.

Once we run this, the global opts have been parsed and ARGV should contain our command, any args it takes, and then any options for that command and args.

e.g. the command might be ‘edit-version’ and the args are a title, and a version to edit. Anything after that are the options for doing the editing (unless we are using –walkthru)



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/xolo/admin/command_line.rb', line 166

def parse_command_cli
  # This gets the command (like config or add-title) and any args
  # like a title and/or a version
  # putting them into cli_cmd
  parse_cmd_and_args # unless cli_cmd.command

  # if we are using --walkthru, all remaining command options are ignored,
  # so just return.
  # The walkthru_cmd_opts will be populated by the interactive
  # process
  return if walkthru?

  # parse_cmd_opts uses Optimist to get the --options that go
  # with the command and its args.
  # we loop thru them (its a hash) and save them into our
  # cli_cmd_opts OpenStruct
  optimist_hash = parse_cmd_opts
  optimist_hash.each { |k, v| cli_cmd_opts[k] = v }

  # Now merge in current_opt_values for anything not given on the cli
  # This is how we inherit values, or apply defaults
  current_opt_values.to_h.each do |k, v|
    next if cli_cmd_opts["#{k}_given"]

    cli_cmd_opts[k] = v unless v.pix_empty?
  end

  # Validate the options given on the commandline
  validate_cli_cmd_opts

  # now cli_cmd_opts contains all the data for
  # processing whatever we're processing, so do the internal consistency checks
  validate_internal_consistency cli_cmd_opts

  # If we got here, everything in Xolo::Admin::Options.cli_cmd_opts is good to go
  # and can be sent to the server for processing.
end

#parse_global_cliHash

Use Optimist to parse the global opts, stopping when it hits a known command This also generates the top level –help output

Returns:

  • (Hash)

    The global opts from the command line, parsed by optimist



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
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/xolo/admin/command_line.rb', line 64

def parse_global_cli
  # set this so its available inside the optimist options block
  executable_file = Xolo::Admin::EXECUTABLE_FILENAME
  usage_line = usage

  Optimist.options do
    banner 'Name:'
    banner "  #{executable_file}, A command-line tool for managing Software Titles and Versions in Xolo."

    banner "\nUsage:"
    banner "  #{usage_line}"

    banner "\nGlobal Options:"

    # add a blank line between each of the cli options in the help output
    # NOTE: chrisl added this to the optimist.rb included in this project.
    insert_blanks

    version Xolo::VERSION

    # The global opts
    ## manually set :version and :help here, or they appear at the bottom of the help
    opt :version, 'Print version and exit'
    opt :help, 'Show this help and exit'

    # This actually sets the optimist global options and their help blurbs
    #
    Xolo::Admin::Options::GLOBAL_OPTIONS.each do |opt_key, deets|
      type = deets[:type] ? :string : :boolean
      opt opt_key, deets[:desc], short: deets[:cli], type: type
    end
    stop_on Xolo::Admin::Options::COMMANDS.keys

    # everything below is just more help output

    banner "\nCommands:"
    Xolo::Admin::Options::COMMANDS.each do |cmd, deets|
      banner format('  %-20s %s', cmd, deets[:desc])
    end

    banner "\nCommand Targets:"
    banner Xolo::Admin::Options::DFT_CMD_TITLE_ARG_BANNER
    banner Xolo::Admin::Options::DFT_CMD_VERSION_ARG_BANNER

    banner "\nCommand Options:"
    banner "  Use '#{executable_file} help command'  or '#{executable_file} command #{Xolo::Admin::Options::HELP_OPT}' to see command-specific help."

    banner "\nExamples:"
    banner "  #{executable_file} add-title google-chrome <options...>"
    banner "    Add a new title 'google-chrome' to Xolo,"
    banner '    specifying all options on the command line'

    banner "\n  #{executable_file} --walkthru add-title google-chrome"
    banner "    Add a new title 'google-chrome' to Xolo,"
    banner '    providing options interactively'

    banner "\n  #{executable_file} edit-title google-chrome <options...>"
    banner "    Edit the existing title 'google-chrome',"
    banner '    specifying all options on the command line'

    banner "\n  #{executable_file} delete-title google-chrome"
    banner "    Delete the existing title 'google-chrome' from Xolo,"
    banner '    along with all of its versions.'

    banner "\n  #{executable_file} add-version google-chrome 95.144.21194 <options...>"
    banner "    Add a new version number 95.144.21194 to the title 'google-chrome'"
    banner '    specifying all options on the command line.'
    banner '    Options not provided are inherited from the previous version, if available.'

    banner "\n  #{executable_file} edit-version google-chrome 95.144.21194 <options...>"
    banner "    Edit version number 95.144.21194 of the title 'google-chrome'"
    banner '    specifying all options on the command line'

    banner "\n  #{executable_file} delete-version google-chrome 95.144.21194"
    banner "    Delete version 95.144.21194 from the title 'google-chrome'"

    banner "\n  #{executable_file} search chrome"
    banner "    List all titles that contain the string 'chrome'"
    banner '    and its available versions'

    banner "\n  #{executable_file} report google-chrome"
    banner "    Report computers with any version of title 'google-chrome' installed"

    banner "\n  #{executable_file} report google-chrome 95.144.21194"
    banner "    Report computers with version 95.144.21194 of title 'google-chrome' installed"

    banner "\n  #{executable_file} list-groups"
    banner '    List all computer groups in Jamf Pro'
  end # Optimist.options
end

#reparse_global_cli_for_help?Boolean

Are we showing the full help? If so, re-parse the global opts

Returns:

  • (Boolean)


287
288
289
290
291
292
293
294
# File 'lib/xolo/admin/command_line.rb', line 287

def reparse_global_cli_for_help?
  cmdstr = cli_cmd.command.to_s
  return false unless cmdstr.empty? || cmdstr.start_with?(Xolo::DASH)

  ARGV.unshift Xolo::Admin::Options::HELP_OPT
  parse_global_cli
  true
end

#title_command?Boolean

Returns does the command we’re running deal with titles?.

Returns:

  • (Boolean)

    does the command we’re running deal with titles?



406
407
408
# File 'lib/xolo/admin/command_line.rb', line 406

def title_command?
  Xolo::Admin::Options::COMMANDS[cli_cmd.command][:target] == :title
end

#title_or_version_command?Boolean

Returns does the command we’re running deal with either titles or versions?.

Returns:

  • (Boolean)

    does the command we’re running deal with either titles or versions?



418
419
420
# File 'lib/xolo/admin/command_line.rb', line 418

def title_or_version_command?
  Xolo::Admin::Options::COMMANDS[cli_cmd.command][:target] == :title_or_version
end

#version_command?Boolean

Returns does the command we’re running deal with versions?.

Returns:

  • (Boolean)

    does the command we’re running deal with versions?



412
413
414
# File 'lib/xolo/admin/command_line.rb', line 412

def version_command?
  Xolo::Admin::Options::COMMANDS[cli_cmd.command][:target] == :version
end