diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d498d89..2c01335 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,6 +109,10 @@ jobs: if: matrix.java == 'temurin@21' && matrix.os == 'ubuntu-latest' run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' doc + - name: Run example (covers reading resources from a jar) + if: matrix.project == 'rootJVM' + run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' example/run + - name: Make target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') run: mkdir -p modules/core/native/target modules/core/jvm/target project/target diff --git a/README.md b/README.md index 0323b45..cdbdb61 100644 --- a/README.md +++ b/README.md @@ -103,8 +103,8 @@ Notes: ```scala val dumboWithResouces = Dumbo.withResources( List( - ResourceFilePath("db/migration/V1__test.sql"), - ResourceFilePath("db/migration/V2__test_b.sql")) + ResourceFilePath("/db/migration/V1__test.sql"), + ResourceFilePath("/db/migration/V2__test_b.sql")) ) ``` diff --git a/build.sbt b/build.sbt index 5057337..11606f0 100644 --- a/build.sbt +++ b/build.sbt @@ -46,6 +46,13 @@ ThisBuild / githubWorkflowBuild := { cond = Some("(matrix.project == 'rootJVM') && (matrix.scala == '2.13')"), ) +: (ThisBuild / githubWorkflowBuild).value } + +ThisBuild / githubWorkflowBuild += WorkflowStep.Sbt( + List("example/run"), + name = Some("Run example (covers reading resources from a jar)"), + cond = Some("matrix.project == 'rootJVM'"), +) + ThisBuild / githubWorkflowBuildMatrixExclusions ++= Seq( MatrixExclude(Map("project" -> "rootNative", "scala" -> "2.12")), MatrixExclude(Map("project" -> "rootNative", "scala" -> "2.13")), diff --git a/modules/core/jvm/src/main/scala-2/dumbo/ResourceFilePath.scala b/modules/core/jvm/src/main/scala-2/dumbo/ResourceFilePath.scala index 6c05e6b..1f2a736 100644 --- a/modules/core/jvm/src/main/scala-2/dumbo/ResourceFilePath.scala +++ b/modules/core/jvm/src/main/scala-2/dumbo/ResourceFilePath.scala @@ -5,10 +5,13 @@ package dumbo import java.io.File +import java.net.URI import java.nio.file.{Path, Paths} +import java.util.zip.ZipFile import scala.jdk.CollectionConverters.* +import cats.effect.Resource import cats.effect.kernel.Sync import cats.implicits.* import dumbo.exception.* @@ -20,14 +23,14 @@ final case class ResourceFilePath(value: String) extends AnyVal { object ResourceFilePath { def fromResourcesDir[F[_]: Sync](location: String): F[List[ResourceFilePath]] = Sync[F].delay(getClass().getClassLoader().getResources(location).asScala.toList).flatMap { - case head :: Nil => + case url :: Nil if url.toString.startsWith("jar:") => listInJar(url.toURI(), location) + case url :: Nil => Sync[F].delay { - val base = Paths.get(head.toURI()) + val base = Paths.get(url.toURI()) val resources = new File(base.toString()).list().map(fileName => apply(Paths.get("/", location, fileName))).toList resources } - case Nil => Sync[F].raiseError(new ResourcesLocationNotFund(s"resource ${location} was not found")) case multiple => Sync[F].raiseError( @@ -38,4 +41,23 @@ object ResourceFilePath { } def apply(p: Path): ResourceFilePath = ResourceFilePath(p.toString()) + + private def listInJar[F[_]: Sync](jarUri: URI, location: String): F[List[ResourceFilePath]] = + Resource.fromAutoCloseable { + Sync[F].delay { + val srcUriStr = jarUri.toString() + val jarFilePath = srcUriStr.slice(srcUriStr.lastIndexOf(":") + 1, srcUriStr.lastIndexOf("!")) + new ZipFile(jarFilePath) + } + }.use { fs => + Sync[F].delay { + fs + .entries() + .asScala + .toList + .filter(_.getName().startsWith(location)) + .map(entry => ResourceFilePath(s"/${entry.getName()}")) + } + } + } diff --git a/modules/example/src/main/scala/ExampleApp.scala b/modules/example/src/main/scala/ExampleApp.scala index 88743c4..209c92d 100644 --- a/modules/example/src/main/scala/ExampleApp.scala +++ b/modules/example/src/main/scala/ExampleApp.scala @@ -17,7 +17,7 @@ object ExampleApp extends IOApp.Simple { database = "postgres", password = Some("postgres"), ), - defaultSchema = "public", + defaultSchema = "dumbo", ) .runMigration .flatMap { result =>