Skip to content

Commit

Permalink
fix version sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
kitlangton committed Jul 1, 2022
1 parent e7a5f15 commit 3f33988
Show file tree
Hide file tree
Showing 7 changed files with 368 additions and 75 deletions.
127 changes: 65 additions & 62 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,18 @@ lazy val root = (project in file("."))
.settings(
name := "scala-update",
libraryDependencies ++= Seq(
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-macros" % zioVersion,
"dev.zio" %% "zio-nio" % zioNioVersion,
"dev.zio" %% "zio-streams" % zioVersion,
"dev.zio" %% "zio-test" % zioVersion % Test,
"dev.zio" %% "zio-test-sbt" % zioVersion % Test,
"io.get-coursier" %% "coursier" % coursierVersion,
"org.scalameta" %% "scalameta" % scalaMetaVersion,
"io.github.kitlangton" %% "zio-tui" % zioTuiVersion
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-cli" % "0.2.7",
"dev.zio" %% "zio-macros" % zioVersion,
"dev.zio" %% "zio-nio" % zioNioVersion,
"dev.zio" %% "zio-json" % "0.3.0-RC9",
"dev.zio" %% "zio-streams" % zioVersion,
"dev.zio" %% "zio-test" % zioVersion % Test,
"dev.zio" %% "zio-test-magnolia" % zioVersion % Test,
"dev.zio" %% "zio-test-sbt" % zioVersion % Test,
"io.get-coursier" %% "coursier" % coursierVersion,
"org.scalameta" %% "scalameta" % scalaMetaVersion,
"io.github.kitlangton" %% "zio-tui" % zioTuiVersion
),
Compile / mainClass := Some("update.Main"),
testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"),
Expand All @@ -58,56 +61,56 @@ lazy val root = (project in file("."))
Global / onChangedBuildSource := ReloadOnSourceChanges

// I use this so I can run `sbt run` in this project. Very lazy hack.
lazy val example = Seq(
"dev.zio" %% "zio" % "1.0.14",
"dev.zio" %% "zio-macros" % "1.0.14",
"dev.zio" %% "zio-nio" % zioNioVersion,
"dev.zio" %% "zio-streams" % "1.0.14",
"dev.zio" %% "zio-test" % "1.0.14" % Test,
"dev.zio" %% "zio-test-sbt" % "1.0.14" % Test,
"io.get-coursier" %% "coursier" % coursierVersion,
"org.scalameta" %% "scalameta" % "4.5.8",
"io.github.kitlangton" %% "zio-tui" % "0.1.1",
"io.github.neurodyne" %% "zio-aws-s3" % "0.4.12",
"io.d11" %% "zhttp" % "2.0.0-RC8",
"com.coralogix" %% "zio-k8s-client" % "1.4.6",
"com.softwaremill.sttp.client3" %% "async-http-client-backend-zio" % "3.6.1",
"nl.vroste" %% "zio-kinesis" % "0.21.1",
"com.vladkopanev" %% "zio-saga-core" % "0.3.0",
"io.scalac" %% "zio-slick-interop" % "0.3",
"com.typesafe.slick" %% "slick-hikaricp" % "3.3.2",
"info.senia" %% "zio-test-akka-http" % "1.0.14",
"io.getquill" %% "quill-jdbc-zio" % "3.18.0",
"dev.zio" %% "zio-akka-cluster" % "0.3.0",
"dev.zio" %% "zio-cache" % "0.2.0",
"dev.zio" %% "zio-config-magnolia" % "3.0.1",
"dev.zio" %% "zio-config-typesafe" % "3.0.1",
"dev.zio" %% "zio-config-refined" % "3.0.1",
"dev.zio" %% "zio-ftp" % "0.3.6",
"dev.zio" %% "zio-json" % "0.3.0-RC8",
// "dev.zio" %% "zio-kafka" % "2.0.0-RC5",
"dev.zio" %% "zio-logging" % "0.5.14",
"dev.zio" %% "zio-metrics-prometheus" % "1.0.14",
"dev.zio" %% "zio-nio" % "1.0.0-RC11",
"dev.zio" %% "zio-optics" % "0.2.0",
"dev.zio" %% "zio-prelude" % "1.0.0-RC9",
"dev.zio" %% "zio-process" % "0.7.0",
"dev.zio" %% "zio-rocksdb" % "0.3.2",
"dev.zio" %% "zio-s3" % "0.3.7",
"dev.zio" %% "zio-schema" % "0.2.0",
"dev.zio" %% "zio-sqs" % "0.4.3",
"dev.zio" %% "zio-opentracing" % "0.8.3",
"io.laserdisc" %% "tamer-db" % "0.18.1",
"io.jaegertracing" % "jaeger-core" % "1.6.0",
"io.jaegertracing" % "jaeger-client" % "1.6.0",
"io.jaegertracing" % "jaeger-zipkin" % "1.6.0",
"io.zipkin.reporter2" % "zipkin-reporter" % "2.16.3",
"io.zipkin.reporter2" % "zipkin-sender-okhttp3" % "2.16.3",
"dev.zio" %% "zio-interop-cats" % "3.3.0",
"dev.zio" %% "zio-interop-scalaz7x" % "7.3.3.0",
"dev.zio" %% "zio-interop-reactivestreams" % "1.3.12",
"dev.zio" %% "zio-interop-twitter" % "20.10.2",
"dev.zio" %% "zio-zmx" % "0.0.13",
"dev.zio" %% "zio-query" % "0.3.0",
"org.polynote" %% "uzhttp" % "0.2.8"
)
//lazy val example = Seq(
// "dev.zio" %% "zio" % "1.0.14",
// "dev.zio" %% "zio-macros" % "1.0.14",
// "dev.zio" %% "zio-nio" % zioNioVersion,
// "dev.zio" %% "zio-streams" % "1.0.14",
// "dev.zio" %% "zio-test" % "1.0.14" % Test,
// "dev.zio" %% "zio-test-sbt" % "1.0.14" % Test,
// "io.get-coursier" %% "coursier" % coursierVersion,
// "org.scalameta" %% "scalameta" % "4.5.8",
// "io.github.kitlangton" %% "zio-tui" % "0.1.1",
// "io.github.neurodyne" %% "zio-aws-s3" % "0.4.12",
// "io.d11" %% "zhttp" % "2.0.0-RC8",
// "com.coralogix" %% "zio-k8s-client" % "1.4.6",
// "com.softwaremill.sttp.client3" %% "async-http-client-backend-zio" % "3.6.1",
// "nl.vroste" %% "zio-kinesis" % "0.21.1",
// "com.vladkopanev" %% "zio-saga-core" % "0.3.0",
// "io.scalac" %% "zio-slick-interop" % "0.3",
// "com.typesafe.slick" %% "slick-hikaricp" % "3.3.2",
// "info.senia" %% "zio-test-akka-http" % "1.0.14",
// "io.getquill" %% "quill-jdbc-zio" % "3.18.0",
// "dev.zio" %% "zio-akka-cluster" % "0.3.0",
// "dev.zio" %% "zio-cache" % "0.2.0",
// "dev.zio" %% "zio-config-magnolia" % "3.0.1",
// "dev.zio" %% "zio-config-typesafe" % "3.0.1",
// "dev.zio" %% "zio-config-refined" % "3.0.1",
// "dev.zio" %% "zio-ftp" % "0.3.6",
// "dev.zio" %% "zio-json" % "0.3.0-RC8",
// // "dev.zio" %% "zio-kafka" % "2.0.0-RC5",
// "dev.zio" %% "zio-logging" % "0.5.14",
// "dev.zio" %% "zio-metrics-prometheus" % "1.0.14",
// "dev.zio" %% "zio-nio" % "1.0.0-RC11",
// "dev.zio" %% "zio-optics" % "0.2.0",
// "dev.zio" %% "zio-prelude" % "1.0.0-RC9",
// "dev.zio" %% "zio-process" % "0.7.0",
// "dev.zio" %% "zio-rocksdb" % "0.3.2",
// "dev.zio" %% "zio-s3" % "0.3.7",
// "dev.zio" %% "zio-schema" % "0.2.0",
// "dev.zio" %% "zio-sqs" % "0.4.3",
// "dev.zio" %% "zio-opentracing" % "0.8.3",
// "io.laserdisc" %% "tamer-db" % "0.18.1",
// "io.jaegertracing" % "jaeger-core" % "1.6.0",
// "io.jaegertracing" % "jaeger-client" % "1.6.0",
// "io.jaegertracing" % "jaeger-zipkin" % "1.6.0",
// "io.zipkin.reporter2" % "zipkin-reporter" % "2.16.3",
// "io.zipkin.reporter2" % "zipkin-sender-okhttp3" % "2.16.3",
// "dev.zio" %% "zio-interop-cats" % "3.3.0",
// "dev.zio" %% "zio-interop-scalaz7x" % "7.3.3.0",
// "dev.zio" %% "zio-interop-reactivestreams" % "1.3.12",
// "dev.zio" %% "zio-interop-twitter" % "20.10.2",
// "dev.zio" %% "zio-zmx" % "0.0.13",
// "dev.zio" %% "zio-query" % "0.3.0",
// "org.polynote" %% "uzhttp" % "0.2.8"
//)
28 changes: 17 additions & 11 deletions src/main/scala/update/Dependency.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,33 @@ object PreRelease {

implicit val ordering: Ordering[PreRelease] = new Ordering[PreRelease] {
private val Re = raw"([A-Za-z]+)(\d+)(\w+)?".r
override def compare(x: PreRelease, y: PreRelease): Int =
override def compare(x: PreRelease, y: PreRelease): Int =
x.value match {
case Re("RC", n, _) =>
y.value match {
case Re("RC", m, _) => n.toInt compare m.toInt
case _ => 1
case _ => 1
}
case Re("M", n, _) =>
y.value match {
case Re("RC", _, _) => -1
case Re("M", m, _) => n.toInt compare m.toInt
case _ => 1
}
y.value match {
case Re("RC", _, _) => -1
case Re("M", m, _) => n.toInt compare m.toInt
case _ => 1
}
case _ => -1
}
}
implicit val ordered = Ordered.orderingToOrdered[PreRelease] _
implicit val ordered = Ordered.orderingToOrdered[PreRelease] _
}

// major.minor.patch-prerelease
final case class Version(value: String) {
lazy val details: VersionDetails =
VersionDetails.fromString(value)

def major: Int = details.major
def minor: Int = details.minor
def patch: Int = details.patch
def major: Int = details.major
def minor: Int = details.minor
def patch: Int = details.patch
def preRelease: Option[PreRelease] = details.preRelease

def isNewerThan(that: Version): Boolean =
Expand All @@ -46,6 +46,12 @@ final case class Version(value: String) {
(major == that.major && minor == that.minor && patch > that.patch) ||
(major == that.major && minor == that.minor && patch == that.patch && preRelease.isEmpty && that.preRelease.isDefined) ||
(major == that.major && minor == that.minor && patch == that.patch && preRelease.isDefined && that.preRelease.isDefined && preRelease.get > that.preRelease.get)

}

object Version {
implicit val ordering: Ordering[Version] =
Ordering.by[Version, (Int, Int, Int, Option[PreRelease])](v => (v.major, v.minor, v.patch, v.preRelease))
}

// group %% artifact % version
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/update/UpdateOptions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ object UpdateOptions {
val patch = current.patch

val allNewerVersions =
available.filter(_.isNewerThan(current))
available.filter(_.isNewerThan(current)).sorted
val majorVersion =
allNewerVersions
.filter(v => ((current.preRelease.isDefined && v.major == major) || v.major > major) && v.preRelease.isEmpty)
Expand Down
160 changes: 160 additions & 0 deletions src/main/scala/update/search/Search.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package update.search

import tui.TUI
import tui.components.Choose
import update.{Artifact, Group, Version}
import view.View
import zio._
import zio.json._

import java.net.URLEncoder
import java.time.Instant
import scala.annotation.tailrec

final case class Payload(
response: Response
)

object Payload {
implicit val codec: JsonCodec[Payload] =
DeriveJsonCodec.gen[Payload]
}

final case class Response(
numFound: Int,
start: Int,
docs: List[Doc]
)

object Response {
implicit val codec: JsonCodec[Response] =
DeriveJsonCodec.gen[Response]
}

final case class Doc(
id: String,
g: String,
a: String,
latestVersion: String,
timestamp: Long
)

final case class SearchResult(
group: Group,
artifact: Artifact,
scalaVersions: List[String],
latestVersion: Version,
lastUpdated: Instant
) {
def render: View =
View.horizontal(
View.text(s"\"${group.value}\"").blue,
View.text("%%").blue.dim,
View.text(s"\"${artifact.value}\"").blue,
View.text("%").blue.dim,
View.text(s"\"${latestVersion.value}\"").blue
)
}

object SearchResult {
def fromDoc(doc: Doc): SearchResult = {
val (artifact, scalaVersion) =
doc.a match {
case s"${artifact}_sjs1_2.11" =>
(artifact, "sjs1_2.11")
case s"${artifact}_sjs1_2.12" =>
(artifact, "sjs1_2.12")
case s"${artifact}_sjs1_2.13" =>
(artifact, "sjs1_2.13")
case s"${artifact}_sjs1_3" =>
(artifact, "sjs1_3")
case s"${artifact}_2.11" =>
(artifact, "2.11")
case s"${artifact}_2.12" =>
(artifact, "2.12")
case s"${artifact}_2.13" =>
(artifact, "2.13")
case s"${artifact}_3" =>
(artifact, "3")
case other =>
(other, "OOPS")
}

SearchResult(
Group(doc.g),
Artifact(artifact),
List(scalaVersion),
Version(doc.latestVersion),
Instant.ofEpochMilli(doc.timestamp)
)
}

// Combine results with same group, artifact and latestVersion but different scala versions
def combineResults(results: List[SearchResult]): List[SearchResult] = {
@tailrec
def loop(
results: List[SearchResult],
acc: List[SearchResult]
): List[SearchResult] =
(results, acc) match {
case (Nil, acc) => acc.reverse
case (r :: rs, a :: as)
if a.group == r.group && a.artifact == r.artifact && a.latestVersion == r.latestVersion =>
loop(rs, a.copy(scalaVersions = a.scalaVersions ++ r.scalaVersions) :: as)
case (r :: rs, acc) =>
loop(rs, r :: acc)
}

loop(results, Nil)
}

}

object Doc {
implicit val codec: JsonCodec[Doc] =
DeriveJsonCodec.gen[Doc]
}

final case class Search() {

def search(query: String): ZIO[Any, Throwable, List[SearchResult]] = {
val urlEncodedQuery = URLEncoder.encode(query, "UTF-8")
val url = s"https://search.maven.org/solrsearch/select?q=$urlEncodedQuery&start=0&rows=60"
for {
string <- ZIO.attempt {
val source = scala.io.Source.fromURL(url)
val string = source.mkString
source.close()
string
}
payload <- ZIO.from(string.fromJson[Payload]).mapError(new Error(_))
} yield SearchResult
.combineResults(payload.response.docs.map(SearchResult.fromDoc))
.distinctBy(sr => (sr.group, sr.artifact, sr.latestVersion))
}

}

object SearchExample extends ZIOAppDefault {

val run: ZIO[Any with ZIOAppArgs with Scope, Any, Any] = {
for {
_ <- ZIO.unit
search = Search()
results <- search.search("zio-cli")
// _ <- Choose.run(results)(_.render)
_ <- ZIO.debug(
View
.vertical(
Chunk(
View.text("LATEST PACKAGES").blue,
View.text("───────────────").blue.dim
) ++
results.map(_.render): _*
)
.render(100, 10)
)
} yield results
}.provide(TUI.live(false))

}
2 changes: 1 addition & 1 deletion src/main/scala/update/versions/VersionsLive.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ final case class VersionsLive() extends Versions {
.map(_.left.map(new Error(_)))
.absolve
.map { case (versions, _) =>
versions.available.map(Version)
versions.available.map(Version(_))
}
.catchSome {
case e if e.getMessage.contains("not found") =>
Expand Down
Loading

0 comments on commit 3f33988

Please sign in to comment.