Skip to content

Commit 3f33988

Browse files
committed
fix version sorting
1 parent e7a5f15 commit 3f33988

File tree

7 files changed

+368
-75
lines changed

7 files changed

+368
-75
lines changed

build.sbt

Lines changed: 65 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,18 @@ lazy val root = (project in file("."))
3030
.settings(
3131
name := "scala-update",
3232
libraryDependencies ++= Seq(
33-
"dev.zio" %% "zio" % zioVersion,
34-
"dev.zio" %% "zio-macros" % zioVersion,
35-
"dev.zio" %% "zio-nio" % zioNioVersion,
36-
"dev.zio" %% "zio-streams" % zioVersion,
37-
"dev.zio" %% "zio-test" % zioVersion % Test,
38-
"dev.zio" %% "zio-test-sbt" % zioVersion % Test,
39-
"io.get-coursier" %% "coursier" % coursierVersion,
40-
"org.scalameta" %% "scalameta" % scalaMetaVersion,
41-
"io.github.kitlangton" %% "zio-tui" % zioTuiVersion
33+
"dev.zio" %% "zio" % zioVersion,
34+
"dev.zio" %% "zio-cli" % "0.2.7",
35+
"dev.zio" %% "zio-macros" % zioVersion,
36+
"dev.zio" %% "zio-nio" % zioNioVersion,
37+
"dev.zio" %% "zio-json" % "0.3.0-RC9",
38+
"dev.zio" %% "zio-streams" % zioVersion,
39+
"dev.zio" %% "zio-test" % zioVersion % Test,
40+
"dev.zio" %% "zio-test-magnolia" % zioVersion % Test,
41+
"dev.zio" %% "zio-test-sbt" % zioVersion % Test,
42+
"io.get-coursier" %% "coursier" % coursierVersion,
43+
"org.scalameta" %% "scalameta" % scalaMetaVersion,
44+
"io.github.kitlangton" %% "zio-tui" % zioTuiVersion
4245
),
4346
Compile / mainClass := Some("update.Main"),
4447
testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"),
@@ -58,56 +61,56 @@ lazy val root = (project in file("."))
5861
Global / onChangedBuildSource := ReloadOnSourceChanges
5962

6063
// I use this so I can run `sbt run` in this project. Very lazy hack.
61-
lazy val example = Seq(
62-
"dev.zio" %% "zio" % "1.0.14",
63-
"dev.zio" %% "zio-macros" % "1.0.14",
64-
"dev.zio" %% "zio-nio" % zioNioVersion,
65-
"dev.zio" %% "zio-streams" % "1.0.14",
66-
"dev.zio" %% "zio-test" % "1.0.14" % Test,
67-
"dev.zio" %% "zio-test-sbt" % "1.0.14" % Test,
68-
"io.get-coursier" %% "coursier" % coursierVersion,
69-
"org.scalameta" %% "scalameta" % "4.5.8",
70-
"io.github.kitlangton" %% "zio-tui" % "0.1.1",
71-
"io.github.neurodyne" %% "zio-aws-s3" % "0.4.12",
72-
"io.d11" %% "zhttp" % "2.0.0-RC8",
73-
"com.coralogix" %% "zio-k8s-client" % "1.4.6",
74-
"com.softwaremill.sttp.client3" %% "async-http-client-backend-zio" % "3.6.1",
75-
"nl.vroste" %% "zio-kinesis" % "0.21.1",
76-
"com.vladkopanev" %% "zio-saga-core" % "0.3.0",
77-
"io.scalac" %% "zio-slick-interop" % "0.3",
78-
"com.typesafe.slick" %% "slick-hikaricp" % "3.3.2",
79-
"info.senia" %% "zio-test-akka-http" % "1.0.14",
80-
"io.getquill" %% "quill-jdbc-zio" % "3.18.0",
81-
"dev.zio" %% "zio-akka-cluster" % "0.3.0",
82-
"dev.zio" %% "zio-cache" % "0.2.0",
83-
"dev.zio" %% "zio-config-magnolia" % "3.0.1",
84-
"dev.zio" %% "zio-config-typesafe" % "3.0.1",
85-
"dev.zio" %% "zio-config-refined" % "3.0.1",
86-
"dev.zio" %% "zio-ftp" % "0.3.6",
87-
"dev.zio" %% "zio-json" % "0.3.0-RC8",
88-
// "dev.zio" %% "zio-kafka" % "2.0.0-RC5",
89-
"dev.zio" %% "zio-logging" % "0.5.14",
90-
"dev.zio" %% "zio-metrics-prometheus" % "1.0.14",
91-
"dev.zio" %% "zio-nio" % "1.0.0-RC11",
92-
"dev.zio" %% "zio-optics" % "0.2.0",
93-
"dev.zio" %% "zio-prelude" % "1.0.0-RC9",
94-
"dev.zio" %% "zio-process" % "0.7.0",
95-
"dev.zio" %% "zio-rocksdb" % "0.3.2",
96-
"dev.zio" %% "zio-s3" % "0.3.7",
97-
"dev.zio" %% "zio-schema" % "0.2.0",
98-
"dev.zio" %% "zio-sqs" % "0.4.3",
99-
"dev.zio" %% "zio-opentracing" % "0.8.3",
100-
"io.laserdisc" %% "tamer-db" % "0.18.1",
101-
"io.jaegertracing" % "jaeger-core" % "1.6.0",
102-
"io.jaegertracing" % "jaeger-client" % "1.6.0",
103-
"io.jaegertracing" % "jaeger-zipkin" % "1.6.0",
104-
"io.zipkin.reporter2" % "zipkin-reporter" % "2.16.3",
105-
"io.zipkin.reporter2" % "zipkin-sender-okhttp3" % "2.16.3",
106-
"dev.zio" %% "zio-interop-cats" % "3.3.0",
107-
"dev.zio" %% "zio-interop-scalaz7x" % "7.3.3.0",
108-
"dev.zio" %% "zio-interop-reactivestreams" % "1.3.12",
109-
"dev.zio" %% "zio-interop-twitter" % "20.10.2",
110-
"dev.zio" %% "zio-zmx" % "0.0.13",
111-
"dev.zio" %% "zio-query" % "0.3.0",
112-
"org.polynote" %% "uzhttp" % "0.2.8"
113-
)
64+
//lazy val example = Seq(
65+
// "dev.zio" %% "zio" % "1.0.14",
66+
// "dev.zio" %% "zio-macros" % "1.0.14",
67+
// "dev.zio" %% "zio-nio" % zioNioVersion,
68+
// "dev.zio" %% "zio-streams" % "1.0.14",
69+
// "dev.zio" %% "zio-test" % "1.0.14" % Test,
70+
// "dev.zio" %% "zio-test-sbt" % "1.0.14" % Test,
71+
// "io.get-coursier" %% "coursier" % coursierVersion,
72+
// "org.scalameta" %% "scalameta" % "4.5.8",
73+
// "io.github.kitlangton" %% "zio-tui" % "0.1.1",
74+
// "io.github.neurodyne" %% "zio-aws-s3" % "0.4.12",
75+
// "io.d11" %% "zhttp" % "2.0.0-RC8",
76+
// "com.coralogix" %% "zio-k8s-client" % "1.4.6",
77+
// "com.softwaremill.sttp.client3" %% "async-http-client-backend-zio" % "3.6.1",
78+
// "nl.vroste" %% "zio-kinesis" % "0.21.1",
79+
// "com.vladkopanev" %% "zio-saga-core" % "0.3.0",
80+
// "io.scalac" %% "zio-slick-interop" % "0.3",
81+
// "com.typesafe.slick" %% "slick-hikaricp" % "3.3.2",
82+
// "info.senia" %% "zio-test-akka-http" % "1.0.14",
83+
// "io.getquill" %% "quill-jdbc-zio" % "3.18.0",
84+
// "dev.zio" %% "zio-akka-cluster" % "0.3.0",
85+
// "dev.zio" %% "zio-cache" % "0.2.0",
86+
// "dev.zio" %% "zio-config-magnolia" % "3.0.1",
87+
// "dev.zio" %% "zio-config-typesafe" % "3.0.1",
88+
// "dev.zio" %% "zio-config-refined" % "3.0.1",
89+
// "dev.zio" %% "zio-ftp" % "0.3.6",
90+
// "dev.zio" %% "zio-json" % "0.3.0-RC8",
91+
// // "dev.zio" %% "zio-kafka" % "2.0.0-RC5",
92+
// "dev.zio" %% "zio-logging" % "0.5.14",
93+
// "dev.zio" %% "zio-metrics-prometheus" % "1.0.14",
94+
// "dev.zio" %% "zio-nio" % "1.0.0-RC11",
95+
// "dev.zio" %% "zio-optics" % "0.2.0",
96+
// "dev.zio" %% "zio-prelude" % "1.0.0-RC9",
97+
// "dev.zio" %% "zio-process" % "0.7.0",
98+
// "dev.zio" %% "zio-rocksdb" % "0.3.2",
99+
// "dev.zio" %% "zio-s3" % "0.3.7",
100+
// "dev.zio" %% "zio-schema" % "0.2.0",
101+
// "dev.zio" %% "zio-sqs" % "0.4.3",
102+
// "dev.zio" %% "zio-opentracing" % "0.8.3",
103+
// "io.laserdisc" %% "tamer-db" % "0.18.1",
104+
// "io.jaegertracing" % "jaeger-core" % "1.6.0",
105+
// "io.jaegertracing" % "jaeger-client" % "1.6.0",
106+
// "io.jaegertracing" % "jaeger-zipkin" % "1.6.0",
107+
// "io.zipkin.reporter2" % "zipkin-reporter" % "2.16.3",
108+
// "io.zipkin.reporter2" % "zipkin-sender-okhttp3" % "2.16.3",
109+
// "dev.zio" %% "zio-interop-cats" % "3.3.0",
110+
// "dev.zio" %% "zio-interop-scalaz7x" % "7.3.3.0",
111+
// "dev.zio" %% "zio-interop-reactivestreams" % "1.3.12",
112+
// "dev.zio" %% "zio-interop-twitter" % "20.10.2",
113+
// "dev.zio" %% "zio-zmx" % "0.0.13",
114+
// "dev.zio" %% "zio-query" % "0.3.0",
115+
// "org.polynote" %% "uzhttp" % "0.2.8"
116+
//)

src/main/scala/update/Dependency.scala

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,33 @@ object PreRelease {
1111

1212
implicit val ordering: Ordering[PreRelease] = new Ordering[PreRelease] {
1313
private val Re = raw"([A-Za-z]+)(\d+)(\w+)?".r
14-
override def compare(x: PreRelease, y: PreRelease): Int =
14+
override def compare(x: PreRelease, y: PreRelease): Int =
1515
x.value match {
1616
case Re("RC", n, _) =>
1717
y.value match {
1818
case Re("RC", m, _) => n.toInt compare m.toInt
19-
case _ => 1
19+
case _ => 1
2020
}
2121
case Re("M", n, _) =>
22-
y.value match {
23-
case Re("RC", _, _) => -1
24-
case Re("M", m, _) => n.toInt compare m.toInt
25-
case _ => 1
26-
}
22+
y.value match {
23+
case Re("RC", _, _) => -1
24+
case Re("M", m, _) => n.toInt compare m.toInt
25+
case _ => 1
26+
}
2727
case _ => -1
2828
}
2929
}
30-
implicit val ordered = Ordered.orderingToOrdered[PreRelease] _
30+
implicit val ordered = Ordered.orderingToOrdered[PreRelease] _
3131
}
3232

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

38-
def major: Int = details.major
39-
def minor: Int = details.minor
40-
def patch: Int = details.patch
38+
def major: Int = details.major
39+
def minor: Int = details.minor
40+
def patch: Int = details.patch
4141
def preRelease: Option[PreRelease] = details.preRelease
4242

4343
def isNewerThan(that: Version): Boolean =
@@ -46,6 +46,12 @@ final case class Version(value: String) {
4646
(major == that.major && minor == that.minor && patch > that.patch) ||
4747
(major == that.major && minor == that.minor && patch == that.patch && preRelease.isEmpty && that.preRelease.isDefined) ||
4848
(major == that.major && minor == that.minor && patch == that.patch && preRelease.isDefined && that.preRelease.isDefined && preRelease.get > that.preRelease.get)
49+
50+
}
51+
52+
object Version {
53+
implicit val ordering: Ordering[Version] =
54+
Ordering.by[Version, (Int, Int, Int, Option[PreRelease])](v => (v.major, v.minor, v.patch, v.preRelease))
4955
}
5056

5157
// group %% artifact % version

src/main/scala/update/UpdateOptions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ object UpdateOptions {
2424
val patch = current.patch
2525

2626
val allNewerVersions =
27-
available.filter(_.isNewerThan(current))
27+
available.filter(_.isNewerThan(current)).sorted
2828
val majorVersion =
2929
allNewerVersions
3030
.filter(v => ((current.preRelease.isDefined && v.major == major) || v.major > major) && v.preRelease.isEmpty)
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package update.search
2+
3+
import tui.TUI
4+
import tui.components.Choose
5+
import update.{Artifact, Group, Version}
6+
import view.View
7+
import zio._
8+
import zio.json._
9+
10+
import java.net.URLEncoder
11+
import java.time.Instant
12+
import scala.annotation.tailrec
13+
14+
final case class Payload(
15+
response: Response
16+
)
17+
18+
object Payload {
19+
implicit val codec: JsonCodec[Payload] =
20+
DeriveJsonCodec.gen[Payload]
21+
}
22+
23+
final case class Response(
24+
numFound: Int,
25+
start: Int,
26+
docs: List[Doc]
27+
)
28+
29+
object Response {
30+
implicit val codec: JsonCodec[Response] =
31+
DeriveJsonCodec.gen[Response]
32+
}
33+
34+
final case class Doc(
35+
id: String,
36+
g: String,
37+
a: String,
38+
latestVersion: String,
39+
timestamp: Long
40+
)
41+
42+
final case class SearchResult(
43+
group: Group,
44+
artifact: Artifact,
45+
scalaVersions: List[String],
46+
latestVersion: Version,
47+
lastUpdated: Instant
48+
) {
49+
def render: View =
50+
View.horizontal(
51+
View.text(s"\"${group.value}\"").blue,
52+
View.text("%%").blue.dim,
53+
View.text(s"\"${artifact.value}\"").blue,
54+
View.text("%").blue.dim,
55+
View.text(s"\"${latestVersion.value}\"").blue
56+
)
57+
}
58+
59+
object SearchResult {
60+
def fromDoc(doc: Doc): SearchResult = {
61+
val (artifact, scalaVersion) =
62+
doc.a match {
63+
case s"${artifact}_sjs1_2.11" =>
64+
(artifact, "sjs1_2.11")
65+
case s"${artifact}_sjs1_2.12" =>
66+
(artifact, "sjs1_2.12")
67+
case s"${artifact}_sjs1_2.13" =>
68+
(artifact, "sjs1_2.13")
69+
case s"${artifact}_sjs1_3" =>
70+
(artifact, "sjs1_3")
71+
case s"${artifact}_2.11" =>
72+
(artifact, "2.11")
73+
case s"${artifact}_2.12" =>
74+
(artifact, "2.12")
75+
case s"${artifact}_2.13" =>
76+
(artifact, "2.13")
77+
case s"${artifact}_3" =>
78+
(artifact, "3")
79+
case other =>
80+
(other, "OOPS")
81+
}
82+
83+
SearchResult(
84+
Group(doc.g),
85+
Artifact(artifact),
86+
List(scalaVersion),
87+
Version(doc.latestVersion),
88+
Instant.ofEpochMilli(doc.timestamp)
89+
)
90+
}
91+
92+
// Combine results with same group, artifact and latestVersion but different scala versions
93+
def combineResults(results: List[SearchResult]): List[SearchResult] = {
94+
@tailrec
95+
def loop(
96+
results: List[SearchResult],
97+
acc: List[SearchResult]
98+
): List[SearchResult] =
99+
(results, acc) match {
100+
case (Nil, acc) => acc.reverse
101+
case (r :: rs, a :: as)
102+
if a.group == r.group && a.artifact == r.artifact && a.latestVersion == r.latestVersion =>
103+
loop(rs, a.copy(scalaVersions = a.scalaVersions ++ r.scalaVersions) :: as)
104+
case (r :: rs, acc) =>
105+
loop(rs, r :: acc)
106+
}
107+
108+
loop(results, Nil)
109+
}
110+
111+
}
112+
113+
object Doc {
114+
implicit val codec: JsonCodec[Doc] =
115+
DeriveJsonCodec.gen[Doc]
116+
}
117+
118+
final case class Search() {
119+
120+
def search(query: String): ZIO[Any, Throwable, List[SearchResult]] = {
121+
val urlEncodedQuery = URLEncoder.encode(query, "UTF-8")
122+
val url = s"https://search.maven.org/solrsearch/select?q=$urlEncodedQuery&start=0&rows=60"
123+
for {
124+
string <- ZIO.attempt {
125+
val source = scala.io.Source.fromURL(url)
126+
val string = source.mkString
127+
source.close()
128+
string
129+
}
130+
payload <- ZIO.from(string.fromJson[Payload]).mapError(new Error(_))
131+
} yield SearchResult
132+
.combineResults(payload.response.docs.map(SearchResult.fromDoc))
133+
.distinctBy(sr => (sr.group, sr.artifact, sr.latestVersion))
134+
}
135+
136+
}
137+
138+
object SearchExample extends ZIOAppDefault {
139+
140+
val run: ZIO[Any with ZIOAppArgs with Scope, Any, Any] = {
141+
for {
142+
_ <- ZIO.unit
143+
search = Search()
144+
results <- search.search("zio-cli")
145+
// _ <- Choose.run(results)(_.render)
146+
_ <- ZIO.debug(
147+
View
148+
.vertical(
149+
Chunk(
150+
View.text("LATEST PACKAGES").blue,
151+
View.text("───────────────").blue.dim
152+
) ++
153+
results.map(_.render): _*
154+
)
155+
.render(100, 10)
156+
)
157+
} yield results
158+
}.provide(TUI.live(false))
159+
160+
}

src/main/scala/update/versions/VersionsLive.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ final case class VersionsLive() extends Versions {
3838
.map(_.left.map(new Error(_)))
3939
.absolve
4040
.map { case (versions, _) =>
41-
versions.available.map(Version)
41+
versions.available.map(Version(_))
4242
}
4343
.catchSome {
4444
case e if e.getMessage.contains("not found") =>

0 commit comments

Comments
 (0)