Skip to content

Commit 5998489

Browse files
authored
Merge pull request #945 from fthomas/topic/kv-store
Use a common implementation for JSON repositories
2 parents b1f7668 + cd3e701 commit 5998489

File tree

10 files changed

+98
-193
lines changed

10 files changed

+98
-193
lines changed

modules/core/src/main/scala/org/scalasteward/core/application/Context.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import org.scalasteward.core.sbt.SbtAlg
3434
import org.scalasteward.core.scalafmt.ScalafmtAlg
3535
import org.scalasteward.core.update.json.JsonUpdateRepository
3636
import org.scalasteward.core.update.{FilterAlg, UpdateRepository, UpdateService}
37-
import org.scalasteward.core.util.{DateTimeAlg, HttpExistenceClient, HttpJsonClient}
37+
import org.scalasteward.core.util._
3838
import org.scalasteward.core.vcs.data.AuthenticatedUser
3939
import org.scalasteward.core.vcs.{VCSApiAlg, VCSExtraAlg, VCSRepoAlg, VCSSelection}
4040

@@ -58,17 +58,20 @@ object Context {
5858
implicit val gitAlg: GitAlg[F] = GitAlg.create[F]
5959
implicit val httpJsonClient: HttpJsonClient[F] = new HttpJsonClient[F]
6060
implicit val httpExistenceClient: HttpExistenceClient[F] = new HttpExistenceClient[F]
61-
implicit val repoCacheRepository: RepoCacheRepository[F] = new JsonRepoCacheRepository[F]
61+
implicit val repoCacheRepository: RepoCacheRepository[F] =
62+
new JsonRepoCacheRepository[F](new JsonKeyValueStore("repos", "6"))
6263
val vcsSelection = new VCSSelection[F]
6364
implicit val vcsApiAlg: VCSApiAlg[F] = vcsSelection.getAlg(config)
6465
implicit val vcsRepoAlg: VCSRepoAlg[F] = VCSRepoAlg.create[F](config, gitAlg)
6566
implicit val vcsExtraAlg: VCSExtraAlg[F] = VCSExtraAlg.create[F]
66-
implicit val pullRequestRepo: PullRequestRepository[F] = new JsonPullRequestRepo[F]
67+
implicit val pullRequestRepo: PullRequestRepository[F] =
68+
new JsonPullRequestRepo[F](new JsonKeyValueStore("prs", "3"))
6769
implicit val scalafmtAlg: ScalafmtAlg[F] = ScalafmtAlg.create[F]
6870
implicit val sbtAlg: SbtAlg[F] = SbtAlg.create[F]
6971
implicit val repoCacheAlg: RepoCacheAlg[F] = new RepoCacheAlg[F]
7072
implicit val editAlg: EditAlg[F] = new EditAlg[F]
71-
implicit val updateRepository: UpdateRepository[F] = new JsonUpdateRepository[F]
73+
implicit val updateRepository: UpdateRepository[F] =
74+
new JsonUpdateRepository[F](new JsonKeyValueStore("updates", "3"))
7275
implicit val coursierAlg: CoursierAlg[F] = CoursierAlg.create
7376
implicit val nurtureAlg: NurtureAlg[F] = new NurtureAlg[F]
7477
implicit val updateService: UpdateService[F] = new UpdateService[F]

modules/core/src/main/scala/org/scalasteward/core/nurture/json/JsonPullRequestRepo.scala

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,18 @@
1616

1717
package org.scalasteward.core.nurture.json
1818

19-
import better.files.File
19+
import cats.FlatMap
2020
import cats.implicits._
21-
import io.circe.parser.decode
22-
import io.circe.syntax._
2321
import org.http4s.Uri
2422
import org.scalasteward.core.data.{Dependency, Update}
2523
import org.scalasteward.core.git.Sha1
26-
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
2724
import org.scalasteward.core.nurture.PullRequestRepository
2825
import org.scalasteward.core.update.UpdateService
29-
import org.scalasteward.core.util.MonadThrowable
26+
import org.scalasteward.core.util.JsonKeyValueStore
3027
import org.scalasteward.core.vcs.data.{PullRequestState, Repo}
3128

32-
class JsonPullRequestRepo[F[_]](
33-
implicit
34-
fileAlg: FileAlg[F],
35-
workspaceAlg: WorkspaceAlg[F],
36-
F: MonadThrowable[F]
29+
final class JsonPullRequestRepo[F[_]: FlatMap](
30+
kvStore: JsonKeyValueStore[F, Repo, Map[String, PullRequestData]]
3731
) extends PullRequestRepository[F] {
3832
override def createOrUpdate(
3933
repo: Repo,
@@ -42,42 +36,26 @@ class JsonPullRequestRepo[F[_]](
4236
update: Update,
4337
state: PullRequestState
4438
): F[Unit] =
45-
readJson.flatMap { store =>
46-
val updated = store.store.get(repo) match {
39+
kvStore.read.flatMap { store =>
40+
val updated = store.get(repo) match {
4741
case Some(prs) => prs.updated(url.toString(), PullRequestData(baseSha1, update, state))
4842
case None => Map(url.toString() -> PullRequestData(baseSha1, update, state))
4943
}
50-
writeJson(PullRequestStore(store.store.updated(repo, updated)))
44+
kvStore.write(store.updated(repo, updated))
5145
}
5246

5347
override def findPullRequest(
5448
repo: Repo,
5549
dependency: Dependency,
5650
newVersion: String
5751
): F[Option[(Uri, Sha1, PullRequestState)]] =
58-
readJson.map { store =>
59-
val pullRequests = store.store.get(repo).fold(List.empty[(String, PullRequestData)])(_.toList)
52+
kvStore.read.map { store =>
53+
val pullRequests = store.get(repo).fold(List.empty[(String, PullRequestData)])(_.toList)
6054
pullRequests
6155
.find {
6256
case (_, data) =>
6357
UpdateService.isUpdateFor(data.update, dependency) && data.update.nextVersion === newVersion
6458
}
6559
.map { case (url, data) => (Uri.unsafeFromString(url), data.baseSha1, data.state) }
6660
}
67-
68-
def jsonFile: F[File] =
69-
workspaceAlg.rootDir.map(_ / "prs_v02.json")
70-
71-
def readJson: F[PullRequestStore] =
72-
jsonFile.flatMap { file =>
73-
fileAlg.readFile(file).flatMap {
74-
case Some(content) => F.fromEither(decode[PullRequestStore](content))
75-
case None => F.pure(PullRequestStore(Map.empty))
76-
}
77-
}
78-
79-
def writeJson(store: PullRequestStore): F[Unit] =
80-
jsonFile.flatMap { file =>
81-
fileAlg.writeFile(file, store.asJson.toString)
82-
}
8361
}

modules/core/src/main/scala/org/scalasteward/core/nurture/json/PullRequestStore.scala

Lines changed: 0 additions & 31 deletions
This file was deleted.

modules/core/src/main/scala/org/scalasteward/core/repocache/json/JsonRepoCacheRepository.scala

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,24 @@
1616

1717
package org.scalasteward.core.repocache.json
1818

19-
import better.files.File
19+
import cats.Functor
2020
import cats.implicits._
21-
import io.circe.parser.decode
22-
import io.circe.syntax._
2321
import org.scalasteward.core.data.Dependency
24-
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
2522
import org.scalasteward.core.repocache.{RepoCache, RepoCacheRepository}
26-
import org.scalasteward.core.util.MonadThrowable
23+
import org.scalasteward.core.util.JsonKeyValueStore
2724
import org.scalasteward.core.vcs.data.Repo
2825

29-
final class JsonRepoCacheRepository[F[_]](
30-
implicit
31-
fileAlg: FileAlg[F],
32-
workspaceAlg: WorkspaceAlg[F],
33-
F: MonadThrowable[F]
26+
final class JsonRepoCacheRepository[F[_]: Functor](
27+
kvStore: JsonKeyValueStore[F, Repo, RepoCache]
3428
) extends RepoCacheRepository[F] {
3529
override def findCache(repo: Repo): F[Option[RepoCache]] =
36-
readJson.map(_.store.get(repo))
30+
kvStore.get(repo)
3731

3832
override def updateCache(repo: Repo, repoCache: RepoCache): F[Unit] =
39-
readJson.flatMap { store =>
40-
writeJson(RepoStore(store.store.updated(repo, repoCache)))
41-
}
33+
kvStore.put(repo, repoCache)
4234

4335
override def getDependencies(repos: List[Repo]): F[List[Dependency]] =
44-
readJson.map(_.store.filterKeys(repos.contains).values.flatMap(_.dependencies).toList.distinct)
45-
46-
def jsonFile: F[File] =
47-
workspaceAlg.rootDir.map(_ / "repos_v05.json")
48-
49-
def readJson: F[RepoStore] =
50-
jsonFile.flatMap { file =>
51-
fileAlg.readFile(file).flatMap {
52-
case Some(content) => F.fromEither(decode[RepoStore](content))
53-
case None => F.pure(RepoStore(Map.empty))
54-
}
55-
}
56-
57-
def writeJson(store: RepoStore): F[Unit] =
58-
jsonFile.flatMap { file =>
59-
fileAlg.writeFile(file, store.asJson.toString)
36+
kvStore.read.map {
37+
_.filterKeys(repos.contains).values.flatMap(_.dependencies).toList.distinct
6038
}
6139
}

modules/core/src/main/scala/org/scalasteward/core/repocache/json/RepoStore.scala

Lines changed: 0 additions & 32 deletions
This file was deleted.

modules/core/src/main/scala/org/scalasteward/core/update/json/JsonUpdateRepository.scala

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,42 +16,23 @@
1616

1717
package org.scalasteward.core.update.json
1818

19-
import better.files.File
19+
import cats.FlatMap
2020
import cats.implicits._
21-
import io.circe.parser.decode
22-
import io.circe.syntax._
2321
import org.scalasteward.core.data.Update
24-
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
2522
import org.scalasteward.core.update.UpdateRepository
26-
import org.scalasteward.core.util.MonadThrowable
23+
import org.scalasteward.core.util.JsonKeyValueStore
2724

28-
// WIP
29-
class JsonUpdateRepository[F[_]](
30-
implicit
31-
fileAlg: FileAlg[F],
32-
workspaceAlg: WorkspaceAlg[F],
33-
F: MonadThrowable[F]
25+
final class JsonUpdateRepository[F[_]: FlatMap](
26+
kvStore: JsonKeyValueStore[F, String, List[Update.Single]]
3427
) extends UpdateRepository[F] {
28+
private val key = "updates"
3529

3630
override def deleteAll: F[Unit] =
37-
writeJson(UpdateStore(Set.empty))
31+
kvStore.write(Map.empty)
3832

3933
override def saveMany(updates: List[Update.Single]): F[Unit] =
40-
readJson.map(s => UpdateStore(s.store ++ updates)).flatMap(writeJson)
41-
42-
def jsonFile: F[File] =
43-
workspaceAlg.rootDir.map(_ / "updates_v02.json")
44-
45-
def readJson: F[UpdateStore] =
46-
jsonFile.flatMap { file =>
47-
fileAlg.readFile(file).flatMap {
48-
case Some(content) => F.fromEither(decode[UpdateStore](content))
49-
case None => F.pure(UpdateStore(Set.empty))
50-
}
51-
}
52-
53-
def writeJson(store: UpdateStore): F[Unit] =
54-
jsonFile.flatMap { file =>
55-
fileAlg.writeFile(file, store.asJson.toString)
56-
}
34+
kvStore
35+
.getOrElse(key, List.empty)
36+
.map(_ ++ updates)
37+
.flatMap(list => kvStore.write(Map(key -> list)))
5738
}

modules/core/src/main/scala/org/scalasteward/core/update/json/UpdateStore.scala

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2018-2019 Scala Steward contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.scalasteward.core.util
18+
19+
import better.files.File
20+
import cats.implicits._
21+
import io.circe.parser.decode
22+
import io.circe.syntax._
23+
import io.circe.{Decoder, Encoder, KeyDecoder, KeyEncoder}
24+
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
25+
26+
final class JsonKeyValueStore[F[_], K, V](name: String, schemaVersion: String)(
27+
implicit
28+
fileAlg: FileAlg[F],
29+
workspaceAlg: WorkspaceAlg[F],
30+
F: MonadThrowable[F],
31+
keyDecoder: KeyDecoder[K],
32+
keyEncoder: KeyEncoder[K],
33+
valueDecoder: Decoder[V],
34+
valueEncoder: Encoder[V]
35+
) {
36+
private val filename =
37+
s"${name}_v${schemaVersion}.json"
38+
39+
private val jsonFile: F[File] =
40+
workspaceAlg.rootDir.map(_ / filename)
41+
42+
def get(key: K): F[Option[V]] =
43+
read.map(_.get(key))
44+
45+
def getOrElse(key: K, default: => V): F[V] =
46+
get(key).map(_.getOrElse(default))
47+
48+
def put(key: K, value: V): F[Unit] =
49+
read.map(_.updated(key, value)).flatMap(write)
50+
51+
def read: F[Map[K, V]] =
52+
jsonFile.flatMap(fileAlg.readFile).flatMap {
53+
case Some(content) => F.fromEither(decode[Map[K, V]](content))
54+
case None => F.pure(Map.empty[K, V])
55+
}
56+
57+
def write(store: Map[K, V]): F[Unit] =
58+
jsonFile.flatMap(fileAlg.writeFile(_, store.asJson.toString))
59+
}

modules/core/src/test/scala/org/scalasteward/core/mock/MockContext.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import org.scalasteward.core.repoconfig.RepoConfigAlg
1515
import org.scalasteward.core.sbt.SbtAlg
1616
import org.scalasteward.core.scalafmt.ScalafmtAlg
1717
import org.scalasteward.core.update.FilterAlg
18-
import org.scalasteward.core.util.{BracketThrowable, DateTimeAlg}
18+
import org.scalasteward.core.util.{BracketThrowable, DateTimeAlg, JsonKeyValueStore}
1919
import org.scalasteward.core.vcs.VCSRepoAlg
2020
import org.scalasteward.core.vcs.data.AuthenticatedUser
2121
import scala.concurrent.duration._
@@ -58,7 +58,7 @@ object MockContext {
5858
implicit val gitHubRepoAlg: VCSRepoAlg[MockEff] = VCSRepoAlg.create(config, gitAlg)
5959
implicit val scalafmtAlg: ScalafmtAlg[MockEff] = ScalafmtAlg.create
6060
implicit val cacheRepository: RepoCacheRepository[MockEff] =
61-
new JsonRepoCacheRepository[MockEff]()
61+
new JsonRepoCacheRepository[MockEff](new JsonKeyValueStore("repos", "6"))
6262
implicit val sbtAlg: SbtAlg[MockEff] = SbtAlg.create
6363
implicit val editAlg: EditAlg[MockEff] = new EditAlg[MockEff]
6464
implicit val repoConfigAlg: RepoConfigAlg[MockEff] = new RepoConfigAlg[MockEff]

0 commit comments

Comments
 (0)