Skip to content

Commit 885a6ae

Browse files
committed
Add sbt plugins locally and not globally
`StewardPlugin.scala` is the sbt plugin that outputs all relevant information from a build for consumption by Scala Steward. That plugin has been installed so far globally at the start of Scala Steward into sbt's home directory. With this PR, that plugin is now installed into the local `project/` directories as long as it is needed to run `sbt stewardDependencies`. This change is motivated by #2847 - i.e. only sbt >= 1.3.0 can currently load our sbt plugin. With this change we would be able to load different plugins dependending on a repo's sbt version.
1 parent b483de7 commit 885a6ae

File tree

6 files changed

+68
-90
lines changed

6 files changed

+68
-90
lines changed

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import better.files.File
2020
import cats.effect.{ExitCode, Sync}
2121
import cats.syntax.all._
2222
import fs2.Stream
23-
import org.scalasteward.core.buildtool.sbt.SbtAlg
2423
import org.scalasteward.core.git.GitAlg
2524
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
2625
import org.scalasteward.core.nurture.NurtureAlg
@@ -44,7 +43,6 @@ final class StewardAlg[F[_]](config: Config)(implicit
4443
nurtureAlg: NurtureAlg[F],
4544
pruningAlg: PruningAlg[F],
4645
repoCacheAlg: RepoCacheAlg[F],
47-
sbtAlg: SbtAlg[F],
4846
selfCheckAlg: SelfCheckAlg[F],
4947
workspaceAlg: WorkspaceAlg[F],
5048
F: Sync[F]
@@ -95,7 +93,7 @@ final class StewardAlg[F[_]](config: Config)(implicit
9593
for {
9694
_ <- selfCheckAlg.checkAll
9795
_ <- workspaceAlg.cleanWorkspace
98-
exitCode <- sbtAlg.addGlobalPlugins.surround {
96+
exitCode <-
9997
(config.githubApp.map(getGitHubAppRepos).getOrElse(Stream.empty) ++
10098
readRepos(config.reposFile))
10199
.evalMap(steward)
@@ -109,7 +107,6 @@ final class StewardAlg[F[_]](config: Config)(implicit
109107
s"""The format is "- $$owner/$$repo" or "- $$owner/$$repo:$$branch"."""
110108
logger.warn(msg).as(ExitCode.Success)
111109
}
112-
}
113110
} yield exitCode
114111
}
115112
}

modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/SbtAlg.scala

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,14 @@ import org.scalasteward.core.buildtool.BuildToolAlg
2525
import org.scalasteward.core.buildtool.sbt.command._
2626
import org.scalasteward.core.buildtool.sbt.data.SbtVersion
2727
import org.scalasteward.core.coursier.VersionsCache
28-
import org.scalasteward.core.data.{Dependency, Scope}
28+
import org.scalasteward.core.data.{Dependency, Scope, Version}
2929
import org.scalasteward.core.edit.scalafix.{ScalafixCli, ScalafixMigration}
30-
import org.scalasteward.core.io.{FileAlg, FileData, ProcessAlg, WorkspaceAlg}
30+
import org.scalasteward.core.io.{FileAlg, ProcessAlg, WorkspaceAlg}
3131
import org.scalasteward.core.util.Nel
3232
import org.scalasteward.core.vcs.data.BuildRoot
33-
import org.typelevel.log4cats.Logger
3433

3534
final class SbtAlg[F[_]](config: Config)(implicit
3635
fileAlg: FileAlg[F],
37-
logger: Logger[F],
3836
processAlg: ProcessAlg[F],
3937
scalafixCli: ScalafixCli[F],
4038
workspaceAlg: WorkspaceAlg[F],
@@ -44,17 +42,6 @@ final class SbtAlg[F[_]](config: Config)(implicit
4442
private def getSbtDependency(buildRoot: BuildRoot): F[Option[Dependency]] =
4543
OptionT(getSbtVersion(buildRoot)).subflatMap(sbtDependency).value
4644

47-
private def addGlobalPluginTemporarily(plugin: FileData): Resource[F, Unit] =
48-
Resource.eval(sbtDir).flatMap { dir =>
49-
List("0.13", "1.0").traverse_ { version =>
50-
fileAlg.createTemporarily(dir / version / "plugins" / plugin.name, plugin.content)
51-
}
52-
}
53-
54-
def addGlobalPlugins: Resource[F, Unit] =
55-
Resource.eval(logger.info("Add global sbt plugins")) >>
56-
Resource.eval(stewardPlugin).flatMap(addGlobalPluginTemporarily)
57-
5845
override def containsBuild(buildRoot: BuildRoot): F[Boolean] =
5946
workspaceAlg
6047
.buildRootDir(buildRoot)
@@ -63,18 +50,28 @@ final class SbtAlg[F[_]](config: Config)(implicit
6350
private def getSbtVersion(buildRoot: BuildRoot): F[Option[SbtVersion]] =
6451
for {
6552
buildRootDir <- workspaceAlg.buildRootDir(buildRoot)
66-
maybeProperties <- fileAlg.readFile(buildRootDir / "project" / "build.properties")
53+
maybeProperties <- fileAlg.readFile(buildRootDir / project / "build.properties")
6754
version = maybeProperties.flatMap(parser.parseBuildProperties)
6855
} yield version
6956

7057
override def getDependencies(buildRoot: BuildRoot): F[List[Scope.Dependencies]] =
58+
addStewardPluginTemporarily(buildRoot).surround {
59+
for {
60+
buildRootDir <- workspaceAlg.buildRootDir(buildRoot)
61+
commands = Nel.of(crossStewardDependencies, reloadPlugins, stewardDependencies)
62+
lines <- sbt(commands, buildRootDir)
63+
dependencies = parser.parseDependencies(lines)
64+
additionalDependencies <- getAdditionalDependencies(buildRoot)
65+
} yield additionalDependencies ::: dependencies
66+
}
67+
68+
private def addStewardPluginTemporarily(buildRoot: BuildRoot): Resource[F, Unit] =
7169
for {
72-
buildRootDir <- workspaceAlg.buildRootDir(buildRoot)
73-
commands = Nel.of(crossStewardDependencies, reloadPlugins, stewardDependencies)
74-
lines <- sbt(commands, buildRootDir)
75-
dependencies = parser.parseDependencies(lines)
76-
additionalDependencies <- getAdditionalDependencies(buildRoot)
77-
} yield additionalDependencies ::: dependencies
70+
buildRootDir <- Resource.eval(workspaceAlg.buildRootDir(buildRoot))
71+
plugin <- Resource.eval(stewardPlugin[F])
72+
_ <- fileAlg.createTemporarily(buildRootDir / project / plugin.name, plugin.content)
73+
_ <- fileAlg.createTemporarily(buildRootDir / project / project / plugin.name, plugin.content)
74+
} yield ()
7875

7976
override def runMigration(buildRoot: BuildRoot, migration: ScalafixMigration): F[Unit] =
8077
migration.targetOrDefault match {
@@ -83,31 +80,29 @@ final class SbtAlg[F[_]](config: Config)(implicit
8380
}
8481

8582
private def runSourcesMigration(buildRoot: BuildRoot, migration: ScalafixMigration): F[Unit] =
86-
sbtScalaFixPluginVersion.foreachF { pluginVersion =>
87-
addGlobalPluginTemporarily(scalaStewardScalafixSbt(pluginVersion)).surround {
88-
workspaceAlg.buildRootDir(buildRoot).flatMap { buildRootDir =>
89-
val withScalacOptions =
90-
migration.scalacOptions.fold(Resource.unit[F]) { opts =>
91-
val file = scalaStewardScalafixOptions(opts.toList)
92-
fileAlg.createTemporarily(buildRootDir / file.name, file.content)
93-
}
83+
OptionT(latestSbtScalafixVersion).foreachF { pluginVersion =>
84+
workspaceAlg.buildRootDir(buildRoot).flatMap { buildRootDir =>
85+
val plugin = scalaStewardSbtScalafix(pluginVersion)
86+
fileAlg.createTemporarily(buildRootDir / project / plugin.name, plugin.content).surround {
87+
val withScalacOptions = migration.scalacOptions.fold(Resource.unit[F]) { opts =>
88+
val options = scalaStewardScalafixOptions(opts.toList)
89+
fileAlg.createTemporarily(buildRootDir / options.name, options.content)
90+
}
9491
val scalafixCmds = migration.rewriteRules.map(rule => s"$scalafixAll $rule").toList
9592
withScalacOptions.surround(sbt(Nel(scalafixEnable, scalafixCmds), buildRootDir).void)
9693
}
9794
}
9895
}
9996

100-
private def sbtScalaFixPluginVersion: OptionT[F, String] =
101-
OptionT(
102-
versionsCache
103-
.getVersions(Scope(sbtScalaFixDependency, List(config.defaultResolver)), None)
104-
.map(_.lastOption.map(_.value))
105-
)
97+
private def latestSbtScalafixVersion: F[Option[Version]] =
98+
versionsCache
99+
.getVersions(Scope(sbtScalafixDependency, List(config.defaultResolver)), None)
100+
.map(_.lastOption)
106101

107102
private def runBuildMigration(buildRoot: BuildRoot, migration: ScalafixMigration): F[Unit] =
108103
for {
109104
buildRootDir <- workspaceAlg.buildRootDir(buildRoot)
110-
projectDir = buildRootDir / "project"
105+
projectDir = buildRootDir / project
111106
files0 <- (
112107
fileAlg.walk(buildRootDir, 1).filter(_.extension.contains(".sbt")) ++
113108
fileAlg.walk(projectDir, 3).filter(_.extension.exists(Set(".sbt", ".scala")))
@@ -117,9 +112,6 @@ final class SbtAlg[F[_]](config: Config)(implicit
117112
}
118113
} yield ()
119114

120-
private val sbtDir: F[File] =
121-
fileAlg.home.map(_ / ".sbt")
122-
123115
private def sbt(sbtCommands: Nel[String], repoDir: File): F[List[String]] =
124116
maybeIgnoreOptsFiles(repoDir).surround {
125117
val command =
@@ -133,7 +125,7 @@ final class SbtAlg[F[_]](config: Config)(implicit
133125
processAlg.execSandboxed(command, repoDir)
134126
}
135127

136-
private def maybeIgnoreOptsFiles[A](dir: File): Resource[F, Unit] =
128+
private def maybeIgnoreOptsFiles(dir: File): Resource[F, Unit] =
137129
if (config.ignoreOptsFiles) ignoreOptsFiles(dir) else Resource.unit[F]
138130

139131
private def ignoreOptsFiles(dir: File): Resource[F, Unit] =
@@ -142,4 +134,6 @@ final class SbtAlg[F[_]](config: Config)(implicit
142134
private def getAdditionalDependencies(buildRoot: BuildRoot): F[List[Scope.Dependencies]] =
143135
getSbtDependency(buildRoot)
144136
.map(_.map(dep => Scope(List(dep), List(config.defaultResolver))).toList)
137+
138+
private val project = "project"
145139
}

modules/core/src/main/scala/org/scalasteward/core/buildtool/sbt/package.scala

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,24 @@ package object sbt {
3535
Option.when(version >= Version("1.0.0"))(Dependency(sbtGroupId, sbtArtifactId, version))
3636
}
3737

38-
val sbtScalaFixGroupId = GroupId("ch.epfl.scala")
39-
val sbtScalaFixArtifactId = ArtifactId("sbt-scalafix")
38+
val sbtScalafixGroupId: GroupId = GroupId("ch.epfl.scala")
4039

41-
val sbtScalaFixDependency: Dependency =
40+
val sbtScalafixArtifactId: ArtifactId = ArtifactId("sbt-scalafix")
41+
42+
val sbtScalafixDependency: Dependency =
4243
Dependency(
43-
sbtScalaFixGroupId,
44-
sbtScalaFixArtifactId,
44+
sbtScalafixGroupId,
45+
sbtScalafixArtifactId,
4546
Version(""),
4647
Some(SbtVersion("1.0")),
4748
Some(ScalaVersion("2.12"))
4849
)
4950

50-
def scalaStewardScalafixSbt(version: String): FileData =
51-
FileData(
52-
"scala-steward-scalafix.sbt",
53-
s"""addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "$version")"""
54-
)
51+
def scalaStewardSbtScalafix(version: Version): FileData = {
52+
val content =
53+
s"""addSbtPlugin("${sbtScalafixGroupId.value}" % "${sbtScalafixArtifactId.name}" % "$version")"""
54+
FileData("scala-steward-sbt-scalafix.sbt", content)
55+
}
5556

5657
def scalaStewardScalafixOptions(scalacOptions: List[String]): FileData = {
5758
val args = scalacOptions.map(s => s""""$s"""").mkString(", ")
@@ -63,6 +64,6 @@ package object sbt {
6364
val name = "StewardPlugin.scala"
6465
fileAlg
6566
.readResource(s"${pkg.replace('.', '/')}/$name")
66-
.map(FileData(name, _))
67+
.map(FileData(s"scala-steward-$name", _))
6768
}
6869
}

modules/core/src/main/scala/org/scalasteward/core/edit/hooks/HookExecutor.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import cats.syntax.all._
2222
import org.scalasteward.core.buildtool.sbt.{
2323
sbtArtifactId,
2424
sbtGroupId,
25-
sbtScalaFixArtifactId,
26-
sbtScalaFixGroupId
25+
sbtScalafixArtifactId,
26+
sbtScalafixGroupId
2727
}
2828
import org.scalasteward.core.data._
2929
import org.scalasteward.core.edit.EditAttempt
@@ -123,7 +123,7 @@ object HookExecutor {
123123

124124
// Modules that most likely require the workflow to be regenerated if updated.
125125
private val conditionalSbtGitHubWorkflowGenerateModules =
126-
(sbtGroupId, sbtArtifactId) :: (sbtScalaFixGroupId, sbtScalaFixArtifactId) :: scalaLangModules
126+
(sbtGroupId, sbtArtifactId) :: (sbtScalafixGroupId, sbtScalafixArtifactId) :: scalaLangModules
127127

128128
private def sbtGithubWorkflowGenerateHook(
129129
groupId: GroupId,

modules/core/src/test/scala/org/scalasteward/core/buildtool/BuildToolDispatcherTest.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class BuildToolDispatcherTest extends FunSuite {
3333
Cmd("test", "-f", s"$repoDir/pom.xml"),
3434
Cmd("test", "-f", s"$repoDir/build.sc"),
3535
Cmd("test", "-f", s"$repoDir/build.sbt"),
36+
Cmd("read", "classpath:org/scalasteward/sbt/plugin/StewardPlugin.scala"),
37+
Cmd("write", s"$repoDir/project/scala-steward-StewardPlugin.scala"),
38+
Cmd("write", s"$repoDir/project/project/scala-steward-StewardPlugin.scala"),
3639
Cmd(
3740
repoDir.toString,
3841
"firejail",
@@ -47,6 +50,8 @@ class BuildToolDispatcherTest extends FunSuite {
4750
s";$crossStewardDependencies;$reloadPlugins;$stewardDependencies"
4851
),
4952
Cmd("read", s"$repoDir/project/build.properties"),
53+
Cmd("rm", "-rf", s"$repoDir/project/project/scala-steward-StewardPlugin.scala"),
54+
Cmd("rm", "-rf", s"$repoDir/project/scala-steward-StewardPlugin.scala"),
5055
Cmd("read", s"$repoDir/$scalafmtConfName")
5156
)
5257
)

modules/core/src/test/scala/org/scalasteward/core/buildtool/sbt/SbtAlgTest.scala

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.scalasteward.core.buildtool.sbt
22

3-
import cats.data.Kleisli
43
import cats.effect.unsafe.implicits.global
54
import munit.FunSuite
65
import org.scalasteward.core.buildtool.sbt.command._
@@ -9,30 +8,11 @@ import org.scalasteward.core.edit.scalafix.ScalafixMigration
98
import org.scalasteward.core.mock.MockConfig.{config, mockRoot}
109
import org.scalasteward.core.mock.MockContext.context.sbtAlg
1110
import org.scalasteward.core.mock.MockState
12-
import org.scalasteward.core.mock.MockState.TraceEntry.{Cmd, Log}
11+
import org.scalasteward.core.mock.MockState.TraceEntry.Cmd
1312
import org.scalasteward.core.util.Nel
1413
import org.scalasteward.core.vcs.data.{BuildRoot, Repo}
1514

1615
class SbtAlgTest extends FunSuite {
17-
test("addGlobalPlugins") {
18-
val obtained = sbtAlg.addGlobalPlugins
19-
.surround(Kleisli(_.update(_.exec(List("fa")))))
20-
.runS(MockState.empty)
21-
.unsafeRunSync()
22-
val expected = MockState.empty.copy(
23-
trace = Vector(
24-
Log("Add global sbt plugins"),
25-
Cmd("read", "classpath:org/scalasteward/sbt/plugin/StewardPlugin.scala"),
26-
Cmd("write", s"$mockRoot/.sbt/0.13/plugins/StewardPlugin.scala"),
27-
Cmd("write", s"$mockRoot/.sbt/1.0/plugins/StewardPlugin.scala"),
28-
Cmd("fa"),
29-
Cmd("rm", "-rf", s"$mockRoot/.sbt/1.0/plugins/StewardPlugin.scala"),
30-
Cmd("rm", "-rf", s"$mockRoot/.sbt/0.13/plugins/StewardPlugin.scala")
31-
)
32-
)
33-
assertEquals(obtained, expected)
34-
}
35-
3616
test("getDependencies") {
3717
val repo = Repo("typelevel", "cats")
3818
val buildRoot = BuildRoot(repo, ".")
@@ -42,6 +22,9 @@ class SbtAlgTest extends FunSuite {
4222
val state = sbtAlg.getDependencies(buildRoot).runS(initial).unsafeRunSync()
4323
val expected = initial.copy(
4424
trace = Vector(
25+
Cmd("read", "classpath:org/scalasteward/sbt/plugin/StewardPlugin.scala"),
26+
Cmd("write", s"$repoDir/project/scala-steward-StewardPlugin.scala"),
27+
Cmd("write", s"$repoDir/project/project/scala-steward-StewardPlugin.scala"),
4528
Cmd(
4629
repoDir.toString,
4730
"firejail",
@@ -55,7 +38,9 @@ class SbtAlgTest extends FunSuite {
5538
"-Dsbt.supershell=false",
5639
s";$crossStewardDependencies;$reloadPlugins;$stewardDependencies"
5740
),
58-
Cmd("read", s"$repoDir/project/build.properties")
41+
Cmd("read", s"$repoDir/project/build.properties"),
42+
Cmd("rm", "-rf", s"$repoDir/project/project/scala-steward-StewardPlugin.scala"),
43+
Cmd("rm", "-rf", s"$repoDir/project/scala-steward-StewardPlugin.scala")
5944
)
6045
)
6146
assertEquals(state, expected)
@@ -83,8 +68,7 @@ class SbtAlgTest extends FunSuite {
8368
"read",
8469
s"$mockRoot/workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json"
8570
),
86-
Cmd("write", s"$mockRoot/.sbt/0.13/plugins/scala-steward-scalafix.sbt"),
87-
Cmd("write", s"$mockRoot/.sbt/1.0/plugins/scala-steward-scalafix.sbt"),
71+
Cmd("write", s"$repoDir/project/scala-steward-sbt-scalafix.sbt"),
8872
Cmd(
8973
repoDir.toString,
9074
"firejail",
@@ -98,8 +82,7 @@ class SbtAlgTest extends FunSuite {
9882
"-Dsbt.supershell=false",
9983
s";$scalafixEnable;$scalafixAll github:functional-streams-for-scala/fs2/v1?sha=v1.0.5"
10084
),
101-
Cmd("rm", "-rf", s"$mockRoot/.sbt/1.0/plugins/scala-steward-scalafix.sbt"),
102-
Cmd("rm", "-rf", s"$mockRoot/.sbt/0.13/plugins/scala-steward-scalafix.sbt")
85+
Cmd("rm", "-rf", s"$repoDir/project/scala-steward-sbt-scalafix.sbt")
10386
)
10487
)
10588
assertEquals(state, expected)
@@ -128,8 +111,7 @@ class SbtAlgTest extends FunSuite {
128111
"read",
129112
s"$mockRoot/workspace/store/versions/v2/https/repo1.maven.org/maven2/ch/epfl/scala/sbt-scalafix_2.12_1.0/versions.json"
130113
),
131-
Cmd("write", s"$mockRoot/.sbt/0.13/plugins/scala-steward-scalafix.sbt"),
132-
Cmd("write", s"$mockRoot/.sbt/1.0/plugins/scala-steward-scalafix.sbt"),
114+
Cmd("write", s"$repoDir/project/scala-steward-sbt-scalafix.sbt"),
133115
Cmd("write", s"$repoDir/scala-steward-scalafix-options.sbt"),
134116
Cmd(
135117
repoDir.toString,
@@ -145,14 +127,13 @@ class SbtAlgTest extends FunSuite {
145127
s";$scalafixEnable;$scalafixAll github:cb372/cats/Cats_v2_2_0?sha=235bd7c92e431ab1902db174cf4665b05e08f2f1"
146128
),
147129
Cmd("rm", "-rf", s"$repoDir/scala-steward-scalafix-options.sbt"),
148-
Cmd("rm", "-rf", s"$mockRoot/.sbt/1.0/plugins/scala-steward-scalafix.sbt"),
149-
Cmd("rm", "-rf", s"$mockRoot/.sbt/0.13/plugins/scala-steward-scalafix.sbt")
130+
Cmd("rm", "-rf", s"$repoDir/project/scala-steward-sbt-scalafix.sbt")
150131
)
151132
)
152133
assertEquals(state, expected)
153134
}
154135

155-
private val sbtScalafixVersionJson =
136+
private def sbtScalafixVersionJson =
156137
s"""|{
157138
| "updatedAt" : 9999999999999,
158139
| "versions" : [

0 commit comments

Comments
 (0)