From f2159950b5d06d69dc1f98503a4fac6c2a4afb92 Mon Sep 17 00:00:00 2001 From: "Frank S. Thomas" Date: Thu, 27 Sep 2018 20:18:10 +0200 Subject: [PATCH] Implement JsonDependencyRepository --- .../scalasteward/dependency/Dependency.scala | 5 ++- .../json/JsonDependencyRepository.scala | 36 +++++++++++++++---- .../dependency/json/RepoValues.scala | 10 ++++++ .../scalasteward/dependency/json/Store.scala | 10 ++++++ .../eu/timepit/scalasteward/git/Sha1.scala | 5 ++- .../scalasteward/github/data/Repo.scala | 15 ++++++++ .../timepit/scalasteward/io/FileService.scala | 25 +++++++++++++ 7 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 modules/core/src/main/scala/eu/timepit/scalasteward/io/FileService.scala diff --git a/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/Dependency.scala b/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/Dependency.scala index da68ea0448..1227a19765 100644 --- a/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/Dependency.scala +++ b/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/Dependency.scala @@ -16,8 +16,8 @@ package eu.timepit.scalasteward.dependency -import io.circe.Decoder import io.circe.generic.semiauto._ +import io.circe.{Decoder, Encoder} final case class Dependency( groupId: String, @@ -30,4 +30,7 @@ final case class Dependency( object Dependency { implicit val dependencyDecoder: Decoder[Dependency] = deriveDecoder + + implicit val dependencyEncoder: Encoder[Dependency] = + deriveEncoder } diff --git a/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/JsonDependencyRepository.scala b/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/JsonDependencyRepository.scala index c146bccda6..411cec1cab 100644 --- a/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/JsonDependencyRepository.scala +++ b/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/JsonDependencyRepository.scala @@ -16,22 +16,44 @@ package eu.timepit.scalasteward.dependency.json +import better.files.File +import cats.MonadError +import cats.implicits._ import eu.timepit.scalasteward.application.WorkspaceService import eu.timepit.scalasteward.dependency.{Dependency, DependencyRepository} import eu.timepit.scalasteward.git.Sha1 import eu.timepit.scalasteward.github.data.Repo +import eu.timepit.scalasteward.io.FileService +import io.circe.parser.decode +import io.circe.syntax._ class JsonDependencyRepository[F[_]]( + fileService: FileService[F], workspaceService: WorkspaceService[F] -) extends DependencyRepository[F] { - - workspaceService.root - - // file operations +)(implicit F: MonadError[F, Throwable]) + extends DependencyRepository[F] { override def findSha1(repo: Repo): F[Option[Sha1]] = - ??? + readJson.map(_.store.get(repo).map(_.sha1)) override def setDependencies(repo: Repo, sha1: Sha1, dependencies: List[Dependency]): F[Unit] = - ??? + readJson.flatMap { store => + val updated = store.store.updated(repo, RepoValues(sha1, dependencies)) + writeJson(Store(updated)) + } + + def jsonFile: F[File] = + workspaceService.root.map(_ / "repos.json") + + def readJson: F[Store] = + jsonFile.flatMap { file => + fileService.readFile(file).flatMap { content => + F.fromEither(decode[Store](content)) + } + } + + def writeJson(store: Store): F[Unit] = + jsonFile.flatMap { file => + fileService.writeFile(file, store.asJson.toString) + } } diff --git a/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/RepoValues.scala b/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/RepoValues.scala index 0ec3219e17..9cee903ed2 100644 --- a/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/RepoValues.scala +++ b/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/RepoValues.scala @@ -18,5 +18,15 @@ package eu.timepit.scalasteward.dependency.json import eu.timepit.scalasteward.dependency.Dependency import eu.timepit.scalasteward.git.Sha1 +import io.circe.generic.semiauto._ +import io.circe.{Decoder, Encoder} final case class RepoValues(sha1: Sha1, dependencies: List[Dependency]) + +object RepoValues { + implicit val repoValuesDecoder: Decoder[RepoValues] = + deriveDecoder + + implicit val repoValuesEncoder: Encoder[RepoValues] = + deriveEncoder +} diff --git a/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/Store.scala b/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/Store.scala index b247453753..cd4cdabf55 100644 --- a/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/Store.scala +++ b/modules/core/src/main/scala/eu/timepit/scalasteward/dependency/json/Store.scala @@ -17,5 +17,15 @@ package eu.timepit.scalasteward.dependency.json import eu.timepit.scalasteward.github.data.Repo +import io.circe.generic.semiauto._ +import io.circe.{Decoder, Encoder} final case class Store(store: Map[Repo, RepoValues]) + +object Store { + implicit val storeDecoder: Decoder[Store] = + deriveDecoder + + implicit val storeEncoder: Encoder[Store] = + deriveEncoder +} diff --git a/modules/core/src/main/scala/eu/timepit/scalasteward/git/Sha1.scala b/modules/core/src/main/scala/eu/timepit/scalasteward/git/Sha1.scala index 2696df446d..ddcc37132e 100644 --- a/modules/core/src/main/scala/eu/timepit/scalasteward/git/Sha1.scala +++ b/modules/core/src/main/scala/eu/timepit/scalasteward/git/Sha1.scala @@ -18,7 +18,7 @@ package eu.timepit.scalasteward.git import cats.Eq import cats.implicits._ -import io.circe.Decoder +import io.circe.{Decoder, Encoder} final case class Sha1(value: String) @@ -28,4 +28,7 @@ object Sha1 { implicit val sha1Decoder: Decoder[Sha1] = Decoder[String].map(Sha1.apply) + + implicit val sha1Encoder: Encoder[Sha1] = + Encoder[String].contramap(_.value) } diff --git a/modules/core/src/main/scala/eu/timepit/scalasteward/github/data/Repo.scala b/modules/core/src/main/scala/eu/timepit/scalasteward/github/data/Repo.scala index 428ba0753d..254016c0bc 100644 --- a/modules/core/src/main/scala/eu/timepit/scalasteward/github/data/Repo.scala +++ b/modules/core/src/main/scala/eu/timepit/scalasteward/github/data/Repo.scala @@ -16,9 +16,24 @@ package eu.timepit.scalasteward.github.data +import io.circe.{KeyDecoder, KeyEncoder} + final case class Repo( owner: String, repo: String ) { def show: String = s"$owner:$repo" } + +object Repo { + implicit val repoKeyDecoder: KeyDecoder[Repo] = + KeyDecoder.instance { key => + val parts = key.split('/') + if (parts.length == 2 && parts.forall(_.nonEmpty)) + Some(Repo(parts(0), parts(1))) + else None + } + + implicit val repoKeyEncoder: KeyEncoder[Repo] = + KeyEncoder.instance(repo => s"${repo.owner}/${repo.repo}") +} diff --git a/modules/core/src/main/scala/eu/timepit/scalasteward/io/FileService.scala b/modules/core/src/main/scala/eu/timepit/scalasteward/io/FileService.scala new file mode 100644 index 0000000000..c3779355b8 --- /dev/null +++ b/modules/core/src/main/scala/eu/timepit/scalasteward/io/FileService.scala @@ -0,0 +1,25 @@ +/* + * Copyright 2018 scala-steward contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.timepit.scalasteward.io + +import better.files.File + +trait FileService[F[_]] { + def readFile(file: File): F[String] + + def writeFile(file: File, content: String): F[Unit] +}