All Downloads are FREE. Search and download functionalities are using the official Maven repository.

harness.zio.error.ExecutableError.scala Maven / Gradle / Ivy

package harness.zio.error

import cats.syntax.either.*
import harness.cli.FinalizedParser
import harness.cli.FinalizedParser.Result
import harness.core.*
import harness.zio.*
import zio.json.*

sealed trait ExecutableError[+E]
object ExecutableError {

  final case class External[+E](error: E) extends ExecutableError[E]

  sealed trait Internal extends ExecutableError[Nothing]
  object Internal {
    implicit val jsonEncoder: JsonEncoder[Internal] = {
      implicit val loadErrorEncoder: JsonEncoder[ConfigError.LoadError] = ConfigError.jsonCodec.encoder.narrow
      implicit val readErrorEncoder: JsonEncoder[ConfigError.ReadError] = ConfigError.jsonCodec.encoder.narrow
      implicit val nonSuccessEncoder: JsonEncoder[FinalizedParser.Result.NonSuccess] = JsonEncoder.string.contramap(_.toString)
      DeriveJsonEncoder.gen
    }
  }

  final case class FailedToParseIndexedArgs(message: String) extends ExecutableError.Internal
  final case class FailedToLoadConfig(error: ConfigError.LoadError) extends ExecutableError.Internal
  final case class FailedToReadConfig(error: ConfigError.ReadError) extends ExecutableError.Internal
  final case class MissingSubCommand(options: List[String]) extends ExecutableError.Internal
  final case class InvalidSubCommand(command: String, options: List[String]) extends ExecutableError.Internal
  final case class ParsingFailure(fail: FinalizedParser.Result.NonSuccess) extends ExecutableError.Internal

  implicit def errorLogger[E](implicit eErrorLogger: ErrorLogger[E]): ErrorLogger[ExecutableError[E]] =
    ErrorLogger.make[ExecutableError[E]] {
      case External(error) => eErrorLogger.convert(error)
      case internal: Internal =>
        val message: String = internal match {
          case FailedToParseIndexedArgs(message) =>
            s"Executable failed to parse args: $message"
          case FailedToLoadConfig(error) =>
            error.safeGetMessage
          case FailedToReadConfig(error) =>
            error.safeGetMessage
          case MissingSubCommand(options) =>
            s"Executable is missing sub-command, options:${options.map(o => s"\n  - $o").mkString}"
          case InvalidSubCommand(command, options) =>
            s"Executable received invalid sub-command '$command', options:${options.map(o => s"\n  - $o").mkString}"
          case ParsingFailure(fail) =>
            fail match {
              case Result.ParseFail(fail) => fail.toString // TODO (KR) : enough?
              case Result.InvalidArg(msg) => msg // TODO (KR) : enough?
              case Result.ParamNameConflict(duplicateParam) =>
                s"[Internal Defect] Unable to create CLI parser, param name conflict: ${duplicateParam.showName}"
              case Result.Help(_, _) =>
                "Should not be possible, failed with help message..."
            }
        }

        Logger.LogLevel.Fatal -> message
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy