Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make report be printed in a single print command, refactor printing code #30

Merged
merged 1 commit into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
}

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

import org.jmotor.sbt.out.UpdatesPrinter.wrap
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 sbt.*

/** Component: Description: Date: 2018/2/26
*
* @author
* AI
*/
class UpdatesPrinterSpec extends AnyFunSuite {
import java.io.{ByteArrayOutputStream, PrintStream}
import java.nio.charset.StandardCharsets

/**
* Component: Description: Date: 2018/2/26
*
* @author
* AI
*/
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.uncolored 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 t3 = s"[info] ${wrap("Dependencies", "-", width)}"
val t1 = s"[info] ${wrap("Global 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.uncolored shouldBe "[success ] oraganization:name:0.0.1 √"
t2.uncolored shouldBe "[expired ] oraganization:name:0.0.1 ---> 1.0.0"
t3.uncolored shouldBe "[error ] oraganization:name:0.0.1 updates error, please retry!"
t4.uncolored 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 uncolored: String = s.replaceAll("\u001B\\[[;\\d]*m", "")
}

}