Program.kt

  1. package com.hexagontk.shell

  2. import com.hexagontk.shell.Property.Companion.HELP
  3. import com.hexagontk.shell.Property.Companion.VERSION
  4. import com.hexagontk.shell.formatter.DefaultFormatter
  5. import com.hexagontk.core.CodedException
  6. import com.hexagontk.helpers.requireNotBlank
  7. import java.io.BufferedReader

  8. class Program(
  9.     val version: String? = null,
  10.     val command: Command,
  11.     val formatter: Formatter = DefaultFormatter(),
  12.     val systemSetting: Boolean = false,
  13.     val defaultCommand: List<String> = emptyList(),
  14. ) {
  15.     constructor(
  16.         name: String,
  17.         version: String? = null,
  18.         title: String? = null,
  19.         description: String? = null,
  20.         properties: Set<Property<*>> = emptySet(),
  21.     ) : this(version, Command(name, title, description, properties))

  22.     constructor(
  23.         name: String,
  24.         version: String? = null,
  25.         title: String? = null,
  26.         description: String? = null,
  27.         properties: Set<Property<*>> = emptySet(),
  28.         commands: Set<Command>,
  29.     ) : this(version, Command(name, title, description, properties, commands))

  30.     init {
  31.         requireNotBlank(Program::version)
  32.     }

  33.     fun input(): String? =
  34.         BufferedReader(System.`in`.reader()).use {
  35.             if (it.ready()) it.readText()
  36.             else null
  37.         }

  38.     fun parse(args: Array<out String>): Command =
  39.         parse(args.toList())

  40.     fun parse(args: Iterable<String>): Command =
  41.         process(args)

  42.     internal fun process(args: Iterable<String>): Command {
  43.         val programCommand = command.findCommand(args)
  44.         val subcommands = programCommand.name.split(" ")
  45.         val properties = subcommands.fold(args.toList()) { a, b -> a - b }

  46.         if (programCommand.contains(VERSION, properties))
  47.             throw CodedException(0, formatter.summary(this, programCommand))

  48.         if (programCommand.contains(HELP, properties))
  49.             throw CodedException(0, formatter.help(this, programCommand))

  50.         if (command.subcommands.isNotEmpty() && programCommand == command)
  51.             throw CodedException(400, formatter.help(this, programCommand))

  52.         val parsedCommand = try {
  53.             programCommand.parse(properties)
  54.         }
  55.         catch (e: Exception) {
  56.             val message = formatter.error(this, programCommand, e)
  57.             throw CodedException(400, message, e)
  58.         }

  59.         return parsedCommand
  60.     }
  61. }