Skip to content

Commit

Permalink
make report be printed in a single print command, refactor printing code
Browse files Browse the repository at this point in the history
  • Loading branch information
CyberGear committed Mar 21, 2024
1 parent 35b203c commit 60c59e8
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 48 deletions.
85 changes: 40 additions & 45 deletions src/main/scala/org/jmotor/sbt/out/UpdatesPrinter.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package org.jmotor.sbt.out

import fansi.Color._
import org.apache.ivy.util.StringUtils
import org.jmotor.sbt.dto.Status._
import fansi.Color.*
import org.jmotor.sbt.dto.Status.*
import org.jmotor.sbt.dto.{ModuleStatus, Status}

import scala.util.Properties.lineSeparator as br

/**
* Component: Description: Date: 2016/12/24
*
Expand All @@ -13,61 +14,55 @@ import org.jmotor.sbt.dto.{ModuleStatus, Status}
*/
object UpdatesPrinter {

def printStatus(module: ModuleStatus): Unit = {
val status = module.status
lazy val errorMessages =
if (module.errors.nonEmpty) s"\n${module.errors.mkString("\n")}\n" else "updates error, please retry!"
val (color, message) = status match {
case Expired => Yellow -> s"${Blue("--->")} ${Red(module.lastVersion)}"
case Unreleased => Yellow -> s"${Blue("--->")} ${Red(module.lastVersion)}"
case Success => Green -> Green("")
case Error => Red -> errorMessages
case NotFound => Red -> Red("×")
case s => Red -> Red(s"unknown status ${s.toString}")
}
val length = Status.values.foldLeft(0) { (l, s) =>
val length = s.toString.length
if (length > l) {
length
} else {
l
}
}
val level = status.toString + StringUtils.repeat(" ", length - status.toString.length)
print(s"[${color(level)}] ${module.raw} $message \n")
}

def printReporter(
projectId: String,
plugins: Seq[ModuleStatus],
globalPlugins: Seq[ModuleStatus],
dependencies: Seq[ModuleStatus]
): Unit = {
import fansi._
import fansi.*
val style = Color.LightBlue ++ Reversed.On ++ Bold.On
val titleWidth = 80
val projectTitleWidth = 100
val separator = style(wrap(projectId, " ", projectTitleWidth))
print(s"$separator \n")
if (globalPlugins.nonEmpty) {
print(s"[info] ${wrap("Global Plugins", "-", titleWidth)}\n")
globalPlugins.foreach(printStatus)
}
if (plugins.nonEmpty) {
print(s"[info] ${wrap(" Plugins", "-", titleWidth)}\n")
plugins.foreach(printStatus)
}
if (dependencies.nonEmpty) {
print(s"[info] ${wrap("Dependencies", "-", titleWidth)}\n")
dependencies.foreach(printStatus)
}

val setsWithLabels = Seq(
"Global Plugins" -> globalPlugins,
"Plugins" -> plugins,
"Dependencies" -> dependencies
)

val report = setsWithLabels.foldLeft(separator)((out, data) =>
if (data._2.nonEmpty)
s"""|$out
|[info] ${wrap(data._1, "-", titleWidth)}
|${data._2.map(statusLine).mkString(br)}""".stripMargin
else out
)

println(report)
}

private[out] def wrap(content: String, wrapWith: String, width: Int): String = {
val wrapLength = (width - content.length) / 2
val range = 0 to wrapLength
val wrapStr = range.map(_ => wrapWith).mkString
s"$wrapStr $content $wrapStr"
val spacedContent = s" $content "
val contentLength = spacedContent.length
(wrapWith * width).patch((width - contentLength) / 2, spacedContent, contentLength)
}

def statusLine(module: ModuleStatus): String = {
val status = module.status
lazy val errorMessages =
if (module.errors.nonEmpty) s"$br${module.errors.mkString(br)}$br" else "updates error, please retry!"
val (color, message) = status match {
case Expired | Unreleased => Yellow -> s"${Blue("--->")} ${Red(module.lastVersion)}"
case Success => Green -> Green("")
case Error => Red -> errorMessages
case NotFound => Red -> Red("×")
case s => Red -> Red(s"unknown status ${s.toString}")
}
val padding = Status.values.map(_.toString.length).max - status.toString.length
val level = s"$status${" " * padding}"
s"[${color(level)}] ${module.raw} $message"
}

}
63 changes: 60 additions & 3 deletions src/test/scala/org/jmotor/sbt/out/UpdatesPrinterSpec.scala
Original file line number Diff line number Diff line change
@@ -1,21 +1,78 @@
package org.jmotor.sbt.out

import org.jmotor.sbt.out.UpdatesPrinter.wrap
import sbt.*
import org.jmotor.sbt.dto.{ModuleStatus, Status}
import org.jmotor.sbt.out.UpdatesPrinter.*
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

import java.io.{ByteArrayOutputStream, PrintStream}
import java.nio.charset.StandardCharsets

/** Component: Description: Date: 2018/2/26
*
* @author
* AI
*/
class UpdatesPrinterSpec extends AnyFunSuite {
class UpdatesPrinterSpec extends AnyFunSuite with Matchers{

test("print report") {
val consoleOut = captureConsoleOut(
printReporter(
"mainModule",
Seq(
ModuleStatus("oraganization" % "name" % "0.0.1", Status.Success),
ModuleStatus("oraganization" % "name" % "0.0.1", Status.Unreleased, "1.0.0")
),
Seq(ModuleStatus("oraganization" % "name" % "0.0.1", Status.Expired, "1.0.0")),
Seq(ModuleStatus("oraganization" % "name" % "0.0.1", Status.Unreleased, "1.0.0"))
)
)

consoleOut.uncolor shouldBe
s"""| mainModule${" "}
|[info] -------------------------------- Global Plugins --------------------------------
|[expired ] oraganization:name:0.0.1 ---> 1.0.0
|[info] ----------------------------------- Plugins ------------------------------------
|[success ] oraganization:name:0.0.1 √
|[unreleased] oraganization:name:0.0.1 ---> 1.0.0
|[info] --------------------------------- Dependencies ---------------------------------
|[unreleased] oraganization:name:0.0.1 ---> 1.0.0
|""".stripMargin
}

test("print layout") {
val width = 80
val t1 = s"[info] ${wrap("Global Plugins", "-", width)}"
val t2 = s"[info] ${wrap(" Plugins", "-", width)}"
val t2 = s"[info] ${wrap("Plugins", "-", width)}"
val t3 = s"[info] ${wrap("Dependencies", "-", width)}"
assert(t1.length == t2.length && t2.length == t3.length)
}

test("status line") {
val t1 = statusLine(ModuleStatus("oraganization" % "name" % "0.0.1", Status.Success))
val t2 = statusLine(ModuleStatus("oraganization" % "name" % "0.0.1", Status.Expired, "1.0.0"))
val t3 = statusLine(ModuleStatus("oraganization" % "name" % "0.0.1", Status.Error))
val t4 = statusLine(ModuleStatus("oraganization" % "name" % "0.0.1", Status.Unreleased, "1.0.0"))

t1.uncolor shouldBe "[success ] oraganization:name:0.0.1 √"
t2.uncolor shouldBe "[expired ] oraganization:name:0.0.1 ---> 1.0.0"
t3.uncolor shouldBe "[error ] oraganization:name:0.0.1 updates error, please retry!"
t4.uncolor shouldBe "[unreleased] oraganization:name:0.0.1 ---> 1.0.0"
}

def captureConsoleOut(f: => Any): String = {
val outBuffer = new ByteArrayOutputStream()
val interceptionStream = new PrintStream(outBuffer, false, StandardCharsets.UTF_8)

scala.Console.withOut(interceptionStream)(f)

val output = new String(outBuffer.toByteArray, StandardCharsets.UTF_8)
output
}

implicit class StringImplicits(s: String) {
def uncolor: String = s.replaceAll("\u001B\\[[;\\d]*m", "")
}

}

0 comments on commit 60c59e8

Please sign in to comment.