Skip to content

Commit 6203ee3

Browse files
committed
Add option to pass lib dependencies to coursier
This can be used to add custom url handlers to coursier, so scala-steward could for example reach s3 buckets, google cloud storage or artifactregistry. See https://get-coursier.io/docs/extra.html#extra-protocols and coursier/coursier#1987
1 parent 883f5db commit 6203ee3

File tree

6 files changed

+108
-31
lines changed

6 files changed

+108
-31
lines changed

docs/help.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
All command line arguments for the `scala-steward` application.
44

55
```
6-
Usage: scala-steward --workspace <file> --repos-file <file> [--git-author-name <string>] --git-author-email <string> [--git-author-signing-key <string>] --git-ask-pass <file> [--sign-commits] [--vcs-type <vcs-type>] [--vcs-api-host <uri>] --vcs-login <string> [--do-not-fork] [--ignore-opts-files] [--env-var <name=value>]... [--process-timeout <duration>] [--whitelist <string>]... [--read-only <string>]... [--enable-sandbox | --disable-sandbox] [--max-buffer-size <integer>] [--repo-config <uri>]... [--disable-default-repo-config] [--scalafix-migrations <uri>]... [--disable-default-scalafix-migrations] [--artifact-migrations <uri>]... [--disable-default-artifact-migrations] [--cache-ttl <duration>] [--bitbucket-server-use-default-reviewers] [--gitlab-merge-when-pipeline-succeeds] [--github-app-id <integer> --github-app-key-file <file>] [--url-checker-test-url <uri>] [--default-maven-repo <string>] [--refresh-backoff-period <duration>]
6+
Usage: scala-steward --workspace <file> --repos-file <file> [--git-author-name <string>] --git-author-email <string> [--git-author-signing-key <string>] --git-ask-pass <file> [--sign-commits] [--vcs-type <vcs-type>] [--vcs-api-host <uri>] --vcs-login <string> [--do-not-fork] [--ignore-opts-files] [--env-var <name=value>]... [--process-timeout <duration>] [--whitelist <string>]... [--read-only <string>]... [--enable-sandbox | --disable-sandbox] [--max-buffer-size <integer>] [--repo-config <uri>]... [--disable-default-repo-config] [--scalafix-migrations <uri>]... [--disable-default-scalafix-migrations] [--artifact-migrations <uri>]... [--disable-default-artifact-migrations] [--cache-ttl <duration>] [--bitbucket-server-use-default-reviewers] [--gitlab-merge-when-pipeline-succeeds] [--github-app-id <integer> --github-app-key-file <file>] [--url-checker-test-url <uri>] [--default-maven-repo <string>] [--refresh-backoff-period <duration>] [--coursier-dependencies <string>]...
77
88
99
@@ -76,4 +76,6 @@ Options and flags:
7676
default: https://repo1.maven.org/maven2/
7777
--refresh-backoff-period <duration>
7878
Period of time a failed build won't be triggered again; default: 0days
79+
--coursier-dependencies <string>
80+
Additional coursier dependencies in the format <groupId>:<artifactId>:<version>, i.e. additional URL handlers. (can be used multiple times)
7981
```

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,13 @@ object Cli {
232232
private val gitHubApp: Opts[Option[GitHubApp]] =
233233
(githubAppId, githubAppKeyFile).mapN(GitHubApp.apply).orNone
234234

235+
private val coursierDependencies: Opts[List[String]] =
236+
options[String](
237+
"coursier-dependencies",
238+
"Additional coursier dependencies in the format <groupId>:<artifactId>:<version>, " +
239+
"i.e. additional URL handlers. (can be used multiple times)"
240+
).orEmpty
241+
235242
private val refreshBackoffPeriod: Opts[FiniteDuration] = {
236243
val default = 0.days
237244
val help = "Period of time a failed build won't be triggered again" +
@@ -267,7 +274,8 @@ object Cli {
267274
gitHubApp,
268275
urlCheckerTestUrl,
269276
defaultMavenRepo,
270-
refreshBackoffPeriod
277+
refreshBackoffPeriod,
278+
coursierDependencies
271279
).mapN(Config.apply)
272280

273281
val command: Command[Config] =

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ final case class Config(
6868
githubApp: Option[GitHubApp],
6969
urlCheckerTestUrl: Uri,
7070
defaultResolver: Resolver,
71-
refreshBackoffPeriod: FiniteDuration
71+
refreshBackoffPeriod: FiniteDuration,
72+
coursierDependencies: List[String]
7273
) {
7374
def vcsUser[F[_]](implicit
7475
processAlg: ProcessAlg[F],

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import org.scalasteward.core.buildtool.maven.MavenAlg
2727
import org.scalasteward.core.buildtool.mill.MillAlg
2828
import org.scalasteward.core.buildtool.sbt.SbtAlg
2929
import org.scalasteward.core.client.ClientConfiguration
30-
import org.scalasteward.core.coursier.{CoursierAlg, VersionsCache}
30+
import org.scalasteward.core.coursier.{CoursierAlg, CoursierDependenciesFetchAlg, VersionsCache}
3131
import org.scalasteward.core.edit.EditAlg
3232
import org.scalasteward.core.edit.hooks.HookExecutor
3333
import org.scalasteward.core.edit.scalafix._
@@ -158,7 +158,9 @@ object Context {
158158
implicit val scalafixCli: ScalafixCli[F] = new ScalafixCli[F]
159159
implicit val scalafmtAlg: ScalafmtAlg[F] = new ScalafmtAlg[F](config)
160160
implicit val selfCheckAlg: SelfCheckAlg[F] = new SelfCheckAlg[F](config)
161-
implicit val coursierAlg: CoursierAlg[F] = CoursierAlg.create[F]
161+
implicit val coursierDependenciesFetchAlg: CoursierDependenciesFetchAlg[F] =
162+
CoursierDependenciesFetchAlg.create[F]
163+
implicit val coursierAlg: CoursierAlg[F] = CoursierAlg.create[F](config)
162164
implicit val versionsCache: VersionsCache[F] =
163165
new VersionsCache[F](config.cacheTtl, versionsStore)
164166
implicit val updateAlg: UpdateAlg[F] = new UpdateAlg[F]

modules/core/src/main/scala/org/scalasteward/core/coursier/CoursierAlg.scala

+46-26
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import coursier.cache.{CachePolicy, FileCache}
2323
import coursier.core.{Authentication, Project}
2424
import coursier.{Fetch, Info, Module, ModuleName, Organization}
2525
import org.http4s.Uri
26+
import org.scalasteward.core.application.Config
2627
import org.scalasteward.core.data.Resolver.Credentials
2728
import org.scalasteward.core.data.{Dependency, Resolver, Scope, Version}
2829
import org.scalasteward.core.util.uri
@@ -45,15 +46,29 @@ trait CoursierAlg[F[_]] {
4546
}
4647

4748
object CoursierAlg {
48-
def create[F[_]](implicit
49+
def create[F[_]](config: Config)(implicit
4950
logger: Logger[F],
5051
parallel: Parallel[F],
51-
F: Sync[F]
52+
F: Sync[F],
53+
fetchAlg: CoursierDependenciesFetchAlg[F]
5254
): CoursierAlg[F] = {
53-
val fetch: Fetch[F] = Fetch[F](FileCache[F]())
55+
val fetch: F[Fetch[F]] = fetchAlg
56+
.classLoader(config.coursierDependencies)
57+
.map { loader =>
58+
Fetch[F](
59+
FileCache[F]().withClassLoaders(loader :: Nil)
60+
)
61+
}
5462

55-
val cacheNoTtl: FileCache[F] =
56-
FileCache[F]().withTtl(None).withCachePolicies(List(CachePolicy.Update))
63+
val cacheNoTtl: F[FileCache[F]] =
64+
fetchAlg
65+
.classLoader(config.coursierDependencies)
66+
.map { loader =>
67+
FileCache[F]()
68+
.withTtl(None)
69+
.withCachePolicies(List(CachePolicy.Update))
70+
.withClassLoaders(loader :: Nil)
71+
}
5772

5873
new CoursierAlg[F] {
5974
override def getArtifactUrl(dependency: Scope.Dependency): F[Option[Uri]] =
@@ -63,24 +78,27 @@ object CoursierAlg {
6378
dependency: coursier.Dependency,
6479
repositories: List[coursier.Repository]
6580
): F[Option[Uri]] = {
66-
val fetchArtifacts = fetch
67-
.withArtifactTypes(Set(coursier.Type.pom, coursier.Type.ivy))
68-
.withDependencies(List(dependency))
69-
.withRepositories(repositories)
70-
fetchArtifacts.ioResult.attempt.flatMap {
71-
case Left(throwable) =>
72-
logger.debug(throwable)(s"Failed to fetch artifacts of $dependency").as(None)
73-
case Right(result) =>
74-
val maybeProject = result.resolution.projectCache
75-
.get(dependency.moduleVersion)
76-
.map { case (_, project) => project }
77-
maybeProject.traverseFilter { project =>
78-
getScmUrlOrHomePage(project.info) match {
79-
case Some(url) => F.pure(Some(url))
80-
case None =>
81-
getParentDependency(project).traverseFilter(getArtifactUrlImpl(_, repositories))
81+
val fetchArtifacts = fetch.map(
82+
_.withArtifactTypes(Set(coursier.Type.pom, coursier.Type.ivy))
83+
.withDependencies(List(dependency))
84+
.withRepositories(repositories)
85+
)
86+
fetchArtifacts.flatMap {
87+
_.ioResult.attempt.flatMap {
88+
case Left(throwable) =>
89+
logger.debug(throwable)(s"Failed to fetch artifacts of $dependency").as(None)
90+
case Right(result) =>
91+
val maybeProject = result.resolution.projectCache
92+
.get(dependency.moduleVersion)
93+
.map { case (_, project) => project }
94+
maybeProject.traverseFilter { project =>
95+
getScmUrlOrHomePage(project.info) match {
96+
case Some(url) => F.pure(Some(url))
97+
case None =>
98+
getParentDependency(project).traverseFilter(getArtifactUrlImpl(_, repositories))
99+
}
82100
}
83-
}
101+
}
84102
}
85103
}
86104

@@ -90,10 +108,12 @@ object CoursierAlg {
90108
logger.error(message) >> F.raiseError(new Throwable(message))
91109
case Right(repository) =>
92110
val module = toCoursierModule(dependency)
93-
repository.versions(module, cacheNoTtl.fetch).run.flatMap {
94-
case Left(message) =>
95-
logger.debug(message) >> F.raiseError(new Throwable(message))
96-
case Right((versions, _)) => F.pure(versions.available.map(Version.apply).sorted)
111+
cacheNoTtl.flatMap { cacheNoTtl =>
112+
repository.versions(module, cacheNoTtl.fetch).run.flatMap {
113+
case Left(message) =>
114+
logger.debug(message) >> F.raiseError(new Throwable(message))
115+
case Right((versions, _)) => F.pure(versions.available.map(Version.apply).sorted)
116+
}
97117
}
98118
}
99119

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2018-2022 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.coursier
18+
19+
import cats.Parallel
20+
import cats.effect._
21+
import cats.implicits._
22+
import coursier._
23+
import coursier.cache.FileCache
24+
25+
import java.net.URLClassLoader
26+
27+
/**
28+
* An interface to fetch dependencies for the coursier alg via coursier.
29+
*/
30+
trait CoursierDependenciesFetchAlg[F[_]] {
31+
def classLoader(dependencies: Seq[String]): F[ClassLoader]
32+
}
33+
34+
object CoursierDependenciesFetchAlg {
35+
def create[F[_]](implicit parallel: Parallel[F], F: Sync[F]): CoursierDependenciesFetchAlg[F] =
36+
(dependencies: Seq[String]) =>
37+
Fetch[F](FileCache[F]())
38+
.withDependencies(dependencies.map { dep =>
39+
val Array(org, name, version) = dep.split(':')
40+
Dependency(Module(Organization(org), ModuleName(name)), version)
41+
})
42+
.io
43+
.map(result => new URLClassLoader(result.map(_.toURI.toURL).toArray))
44+
}

0 commit comments

Comments
 (0)