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

com.mchange.sysadmin.core.scala Maven / Gradle / Ivy

package com.mchange.sysadmin

import scala.collection.*
import com.mchange.codegenutil.*
import java.time.{Instant,ZoneId}
import java.time.temporal.ChronoUnit
import java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME

import scala.util.control.NonFatal

class SysadminException( message : String, cause : Throwable = null ) extends Exception(message, cause)

def extractFullStackTrace(t:Throwable) : String =
  val sw = new java.io.StringWriter()
  t.printStackTrace(new java.io.PrintWriter(sw))
  sw.toString()

extension (t : Throwable)
  def fullStackTrace : String = extractFullStackTrace(t)

lazy val hostname : Option[String] =
  try
    Some(os.proc("hostname").call( check=false, stdout = os.Pipe, stderr = os.Pipe ).out.trim())
  catch
    case NonFatal(t) =>  None

def timestamp =
  val now = Instant.now.truncatedTo( ChronoUnit.SECONDS ).atZone(ZoneId.systemDefault())
  ISO_OFFSET_DATE_TIME.format(now)

def defaultTitle( run : Task.Run ) =
  hostname.fold("TASK")(hn => "[" + hn + "]") + ": " + run.task.name + " -- " + (if run.success then "SUCCEEDED" else "FAILED")

def defaultVerticalMessage( run : Task.Run ) =
  val mainSection =
    s"""|=====================================================================
        | ${defaultTitle(run)}
        |=====================================================================
        | Timestamp: ${timestamp}
        | Succeeded overall? ${if run.success then "Yes" else "No"}
        |
        | SEQUENTIAL:
        |${defaultVerticalMessageSequential(run.sequential)}""".stripMargin.trim + LineSep + LineSep

  def cleanupsSectionIfNecessary =
    s"""|-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
        |
        | BEST-ATTEMPT CLEANUPS:
        |${defaultVerticalMessageBestAttemptCleanups(run.bestAttemptCleanUps)}""".stripMargin.trim

  val midsection = if run.bestAttemptCleanUps.isEmpty then "" else (cleanupsSectionIfNecessary + LineSep + LineSep)

  val footer =
    s"""|
        |=====================================================================
        |.   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .""".stripMargin.trim + LineSep

  mainSection + midsection + footer


def defaultVerticalMessageSequential( sequential : List[Step.Run] ) : String =
  val tups = immutable.LazyList.from(1).zip(sequential)
  val untrimmed = tups.foldLeft(""): (accum, next) =>
    accum + (LineSep*2) + defaultVerticalMessage(next)
  untrimmed.trim

def defaultVerticalMessageBestAttemptCleanups( bestAttemptCleanups : List[Step.Run] ) : String =
  val untrimmed = bestAttemptCleanups.foldLeft(""): (accum, next) =>
    accum + (LineSep*2) + defaultVerticalMessage(next)
  untrimmed.trim

def defaultVerticalMessage( run : Step.Run ) : String = defaultVerticalMessage(None, run)

def defaultVerticalMessage( tup : Tuple2[Int,Step.Run]) : String = defaultVerticalMessage(Some(tup(0)),tup(1))

def defaultVerticalMessage( index : Option[Int], run : Step.Run ) : String =
  def action( step : Step ) : String =
    step match
      case exec : Step.Exec => s"Parsed command: ${exec.parsedCommand}"
      case internal : Step.Internal => "Action: "
  val body = run match
    case completed : Step.Run.Completed => defaultVerticalBody(completed)
    case skipped   : Step.Run.Skipped   => defaultVerticalBody(skipped)
  val header =
    s"""|---------------------------------------------------------------------
        | ${index.fold(run.step.name)(i => i.toString + ". " + run.step.name)}
        |---------------------------------------------------------------------
        | ${action(run.step)}
        | Succeeded? ${if run.success then "Yes" else "No"}""".stripMargin.trim
  header + LineSep + body

def defaultVerticalBody(completed : Step.Run.Completed) : String =
  def afterExitCode( step : Step ) : String =
    step match
      case exec : Step.Exec => ""
      case internal : Step.Internal => "(notional)"
  val stdOutContent =
    if completed.result.stepOut.nonEmpty then completed.result.stepOut else ""
  val stdErrContent =
    if completed.result.stepErr.nonEmpty then completed.result.stepErr else ""
  s"""| Exit Code: ${completed.result.exitCode} ${afterExitCode(completed.step)}
      |
      | stdout:
      |${increaseIndent(5)(stdOutContent)}
      |
      | stderr:
      |${increaseIndent(5)(stdErrContent)}""".stripMargin // don't trim, we want the initial space

// Leave this stuff out
// We end up mailing sensitive stuff from the environment
//
//      |
//      | Working directory:
//      |${increaseIndent(5)(completed.step.workingDirectory.toString)}
//      |
//      | Environment:
//      |${increaseIndent(5)(pprint.PPrinter.BlackWhite(completed.step.environment).plainText)}"""

def defaultVerticalBody(skipped : Step.Run.Skipped) : String =
  s"""|
      | SKIPPED!""".stripMargin.trim








© 2015 - 2025 Weber Informatics LLC | Privacy Policy