diff --git a/launcher-implementation/src/main/scala/xsbt/boot/ConfigurationParser.scala b/launcher-implementation/src/main/scala/xsbt/boot/ConfigurationParser.scala index 4677450..396f0b9 100644 --- a/launcher-implementation/src/main/scala/xsbt/boot/ConfigurationParser.scala +++ b/launcher-implementation/src/main/scala/xsbt/boot/ConfigurationParser.scala @@ -204,12 +204,20 @@ class ConfigurationParser { def getRepositories(m: LabelMap): List[Repository.Repository] = { import Repository.{ Ivy, Maven, Predefined } val BootOnly = "bootOnly" + val BootOnlyZero = "bootOnlyZero" val MvnComp = "mavenCompatible" val DescriptorOptional = "descriptorOptional" val DontCheckConsistency = "skipConsistencyCheck" val AllowInsecureProtocol = "allowInsecureProtocol" val OptSet = - Set(BootOnly, MvnComp, DescriptorOptional, DontCheckConsistency, AllowInsecureProtocol) + Set( + BootOnly, + BootOnlyZero, + MvnComp, + DescriptorOptional, + DontCheckConsistency, + AllowInsecureProtocol + ) m.toList.map { case (key, None) => Predefined(key) case (key, Some(BootOnly)) => Predefined(key, true) @@ -224,13 +232,14 @@ class ConfigurationParser { val (optionPart, patterns) = r.tail.partition(OptSet.contains(_)) val options = ( optionPart.contains(BootOnly), + optionPart.contains(BootOnlyZero), optionPart.contains(MvnComp), optionPart.contains(DescriptorOptional), optionPart.contains(DontCheckConsistency), optionPart.contains(AllowInsecureProtocol) ) (patterns, options) match { - case (both :: Nil, (bo, mc, dso, cc, ip)) => + case (both :: Nil, (bo, boz, mc, dso, cc, ip)) => Ivy( key, url, @@ -238,11 +247,12 @@ class ConfigurationParser { both, mavenCompatible = mc, bootOnly = bo, + bootOnlyZero = boz, descriptorOptional = dso, skipConsistencyCheck = cc, allowInsecureProtocol = ip ) - case (ivy :: art :: Nil, (bo, mc, dso, cc, ip)) => + case (ivy :: art :: Nil, (bo, boz, mc, dso, cc, ip)) => Ivy( key, url, @@ -250,14 +260,15 @@ class ConfigurationParser { art, mavenCompatible = mc, bootOnly = bo, + bootOnlyZero = boz, descriptorOptional = dso, skipConsistencyCheck = cc, allowInsecureProtocol = ip ) - case (Nil, (true, false, false, cc, ip)) => - Maven(key, url, bootOnly = true, allowInsecureProtocol = ip) - case (Nil, (false, false, false, false, ip)) => - Maven(key, url, allowInsecureProtocol = ip) + case (Nil, (true, boz, false, false, cc, ip)) => + Maven(key, url, bootOnly = true, bootOnlyZero = boz, allowInsecureProtocol = ip) + case (Nil, (false, boz, false, false, false, ip)) => + Maven(key, url, bootOnly = false, bootOnlyZero = boz, allowInsecureProtocol = ip) case _ => Pre.error("could not parse %s: %s".format(key, value)) } diff --git a/launcher-implementation/src/main/scala/xsbt/boot/CoursierUpdate.scala b/launcher-implementation/src/main/scala/xsbt/boot/CoursierUpdate.scala index 5bbca76..e4f99a9 100644 --- a/launcher-implementation/src/main/scala/xsbt/boot/CoursierUpdate.scala +++ b/launcher-implementation/src/main/scala/xsbt/boot/CoursierUpdate.scala @@ -69,9 +69,9 @@ class CousierUpdate(config: UpdateConfiguration) { if (repositories.isEmpty) Resolve.defaultRepositories else Nil - def apply(target: UpdateTarget, reason: String): UpdateResult = { + def apply(target: UpdateTarget, sbtZero: Boolean, reason: String): UpdateResult = { try { - update(target, reason) + update(target, sbtZero, reason) } catch { case e: Throwable => e.printStackTrace(logWriter) @@ -82,7 +82,7 @@ class CousierUpdate(config: UpdateConfiguration) { } } - private def update(target: UpdateTarget, reason: String): UpdateResult = { + private def update(target: UpdateTarget, sbtZero: Boolean, reason: String): UpdateResult = { val deps = target match { case u: UpdateScala => val scalaVersion = getScalaVersion @@ -154,7 +154,7 @@ class CousierUpdate(config: UpdateConfiguration) { case _ => Nil }) } - update(target, deps) + update(target, sbtZero, deps) } private def detectScalaVersion(dependencySet: Set[Dependency]): Option[String] = { @@ -176,9 +176,15 @@ class CousierUpdate(config: UpdateConfiguration) { /** Runs the resolve and retrieve for the given moduleID, which has had its dependencies added already. */ private def update( target: UpdateTarget, + sbtZero: Boolean, deps: List[Dependency] ): UpdateResult = { - val repos = config.repositories.map(toCoursierRepository) + val repos = config.repositories.flatMap { + case repo: xsbt.boot.Repository.Repository => + if (sbtZero || !repo.bootOnlyZero) Some(toCoursierRepository(repo)) + else None + case repo => Some(toCoursierRepository(repo)) + } val params = scalaVersion match { case Some(sv) if sv != "auto" => ResolutionParams() @@ -334,6 +340,8 @@ class CousierUpdate(config: UpdateConfiguration) { Repositories.sonatype("snapshots") case Jcenter => Repositories.jcenter + case ScalaToolsReleases | ScalaToolsSnapshots => + sys.error(s"unsupported repo: ${p.id}") } } } diff --git a/launcher-implementation/src/main/scala/xsbt/boot/Launch.scala b/launcher-implementation/src/main/scala/xsbt/boot/Launch.scala index 0ff537c..32fcf11 100644 --- a/launcher-implementation/src/main/scala/xsbt/boot/Launch.scala +++ b/launcher-implementation/src/main/scala/xsbt/boot/Launch.scala @@ -233,8 +233,14 @@ class Launch private[xsbt] ( def globalLock: xsbti.GlobalLock = Locks def ivyHome = orNull(ivyOptions.ivyHome) - def ivyRepositories = (repositories: List[xsbti.Repository]).toArray - def appRepositories = ((repositories filterNot (_.bootOnly)): List[xsbti.Repository]).toArray + def ivyRepositories = + ((repositories + .filterNot(_.bootOnlyZero)): List[xsbti.Repository]).toArray + def allRepositories = (repositories: List[xsbti.Repository]).toArray + def appRepositories = + ((repositories + .filterNot(_.bootOnly) + .filterNot(_.bootOnlyZero)): List[xsbti.Repository]).toArray def isOverrideRepositories: Boolean = ivyOptions.isOverrideRepositories def checksums = checksumsList.toArray[String] diff --git a/launcher-implementation/src/main/scala/xsbt/boot/LaunchConfiguration.scala b/launcher-implementation/src/main/scala/xsbt/boot/LaunchConfiguration.scala index 4474aa1..4429bc6 100644 --- a/launcher-implementation/src/main/scala/xsbt/boot/LaunchConfiguration.scala +++ b/launcher-implementation/src/main/scala/xsbt/boot/LaunchConfiguration.scala @@ -211,11 +211,13 @@ object Application { object Repository { trait Repository extends xsbti.Repository { def bootOnly: Boolean + def bootOnlyZero: Boolean } final case class Maven( id: String, url: URL, bootOnly: Boolean = false, + bootOnlyZero: Boolean = false, allowInsecureProtocol: Boolean = false ) extends xsbti.MavenRepository with Repository @@ -226,13 +228,17 @@ object Repository { artifactPattern: String, mavenCompatible: Boolean, bootOnly: Boolean = false, + bootOnlyZero: Boolean = false, descriptorOptional: Boolean = false, skipConsistencyCheck: Boolean = false, allowInsecureProtocol: Boolean = false ) extends xsbti.IvyRepository with Repository - final case class Predefined(id: xsbti.Predefined, bootOnly: Boolean = false) - extends xsbti.PredefinedRepository + final case class Predefined( + id: xsbti.Predefined, + bootOnly: Boolean = false, + bootOnlyZero: Boolean = false + ) extends xsbti.PredefinedRepository with Repository object Predefined { def apply(s: String): Predefined = new Predefined(xsbti.Predefined.toValue(s), false) diff --git a/launcher-implementation/src/main/scala/xsbt/boot/ModuleDefinition.scala b/launcher-implementation/src/main/scala/xsbt/boot/ModuleDefinition.scala index 83e2c42..9997bb8 100644 --- a/launcher-implementation/src/main/scala/xsbt/boot/ModuleDefinition.scala +++ b/launcher-implementation/src/main/scala/xsbt/boot/ModuleDefinition.scala @@ -14,7 +14,11 @@ final class ModuleDefinition( def retrieveCorrupt(missing: Iterable[String]): Nothing = fail(": missing " + missing.mkString(", ")) private def fail(extra: String) = - throw new xsbti.RetrieveException(versionString, "could not retrieve " + failLabel + extra) + throw new xsbti.RetrieveException( + versionString, + "could not retrieve " + failLabel + extra + + " " + configuration.repositories.mkString(", ") + ) private def versionString: String = target match { case _: UpdateScala => configuration.getScalaVersion; case a: UpdateApp => Value.get(a.id.version) diff --git a/launcher-implementation/src/main/scala/xsbt/boot/Update.scala b/launcher-implementation/src/main/scala/xsbt/boot/Update.scala index 28dc04a..8393609 100644 --- a/launcher-implementation/src/main/scala/xsbt/boot/Update.scala +++ b/launcher-implementation/src/main/scala/xsbt/boot/Update.scala @@ -116,6 +116,41 @@ final class Update(config: UpdateConfiguration) { if (realm != null && host != null && user != null && password != null) CredentialsStore.INSTANCE.addCredentials(realm, host, user, password) } + + private[this] def setScalaVariable(settings: IvySettings, scalaVersion: Option[String]): Unit = + scalaVersion match { case Some(sv) => settings.setVariable("scala", sv); case None => } + + // should be the same file as is used in the Ivy module + private lazy val ivyLockFile = new File(settings.getDefaultIvyUserDir, ".sbt.ivy.lock") + lazy val coursierUpdate = new CousierUpdate(config) + var sbtZero = false + + /** The main entry point of this class for use by the Update module. It runs Ivy */ + def apply(target: UpdateTarget, reason: String): UpdateResult = { + val x = Option(System.getProperty("sbt.launcher.coursier")) + sbtZero = target match { + // https://github.com/sbt/sbt/issues/6447 + case u: UpdateApp + if u.id.groupID == "org.scala-sbt" && + u.id.getName == "sbt" && u.id.getVersion.startsWith("0.") => + true + case _ => false + } + val useCousier = x match { + case Some("true") | Some("1") => true + case Some(_) => false + case None => !sbtZero + } + if (useCousier) coursierUpdate(target, sbtZero, reason) + else { + Message.setDefaultLogger(new SbtIvyLogger(logWriter)) + val action = new Callable[UpdateResult] { + def call = lockedApply(target, reason) + } + Locks(ivyLockFile, action) + } + } + private lazy val settings = { addCredentials() val settings = new IvySettings @@ -127,8 +162,6 @@ final class Update(config: UpdateConfiguration) { setScalaVariable(settings, scalaVersion) settings } - private[this] def setScalaVariable(settings: IvySettings, scalaVersion: Option[String]): Unit = - scalaVersion match { case Some(sv) => settings.setVariable("scala", sv); case None => } private lazy val ivy = { val ivy = new Ivy() { private val loggerEngine = new SbtMessageLoggerEngine; @@ -138,33 +171,6 @@ final class Update(config: UpdateConfiguration) { ivy.bind() ivy } - // should be the same file as is used in the Ivy module - private lazy val ivyLockFile = new File(settings.getDefaultIvyUserDir, ".sbt.ivy.lock") - lazy val coursierUpdate = new CousierUpdate(config) - - /** The main entry point of this class for use by the Update module. It runs Ivy */ - def apply(target: UpdateTarget, reason: String): UpdateResult = { - val x = Option(System.getProperty("sbt.launcher.coursier")) - val useCousier = x match { - case Some("true") | Some("1") => true - case Some(_) => false - case None => - target match { - // https://github.com/sbt/sbt/issues/6447 - case u: UpdateApp - if u.id.groupID == "org.scala-sbt" && - u.id.getName == "sbt" && u.id.getVersion.startsWith("0.") => - false - case _ => true - } - } - if (useCousier) coursierUpdate(target, reason) - else { - Message.setDefaultLogger(new SbtIvyLogger(logWriter)) - val action = new Callable[UpdateResult] { def call = lockedApply(target, reason) } - Locks(ivyLockFile, action) - } - } private def lockedApply(target: UpdateTarget, reason: String): UpdateResult = { ivy.pushContext() @@ -449,7 +455,11 @@ final class Update(config: UpdateConfiguration) { } // exclude the local Maven repository for Scala -SNAPSHOTs private def includeRepo(repo: xsbti.Repository) = - !(Repository.isMavenLocal(repo) && isSnapshot(getScalaVersion)) + !(Repository.isMavenLocal(repo) && isSnapshot(getScalaVersion)) && + (sbtZero || (repo match { + case r: Repository.Repository => !r.bootOnlyZero + case _ => true + })) private def isSnapshot(scalaVersion: String) = scalaVersion.endsWith(Snapshot) private[this] val Snapshot = "-SNAPSHOT" private[this] val ChangingPattern = ".*" + Snapshot diff --git a/launcher-implementation/src/test/scala/ConfigurationParserTest.scala b/launcher-implementation/src/test/scala/ConfigurationParserTest.scala index 779afa7..add9121 100644 --- a/launcher-implementation/src/test/scala/ConfigurationParserTest.scala +++ b/launcher-implementation/src/test/scala/ConfigurationParserTest.scala @@ -31,47 +31,92 @@ object ConfigurationParserTest extends verify.BasicTestSuite { repoFileContains( """|[repositories] | id: http://repo1.maven.org, bootOnly, allowInsecureProtocol""".stripMargin, - Repository.Maven("id", new URL("http://repo1.maven.org"), true, true) + Repository.Maven("id", new URL("http://repo1.maven.org"), true, false, true) ) repoFileContains( """|[repositories] | id: https://repo1.maven.org, [orgPath]""".stripMargin, Repository - .Ivy("id", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]", false, false) + .Ivy( + "id", + new URL("https://repo1.maven.org"), + "[orgPath]", + "[orgPath]", + false, + false, + false + ) ) repoFileContains( """|[repositories] | id: https://repo1.maven.org, [orgPath], mavenCompatible""".stripMargin, Repository - .Ivy("id", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]", true, false) + .Ivy( + "id", + new URL("https://repo1.maven.org"), + "[orgPath]", + "[orgPath]", + mavenCompatible = true, + false, + false + ) ) repoFileContains( """|[repositories] | id: https://repo1.maven.org, [orgPath], mavenCompatible, bootOnly""".stripMargin, - Repository.Ivy("id", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]", true, true) + Repository + .Ivy( + "id", + new URL("https://repo1.maven.org"), + "[orgPath]", + "[orgPath]", + mavenCompatible = true, + bootOnly = true, + ) ) repoFileContains( """|[repositories] | id: https://repo1.maven.org, [orgPath], bootOnly, mavenCompatible""".stripMargin, - Repository.Ivy("id", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]", true, true) + Repository + .Ivy( + "id", + new URL("https://repo1.maven.org"), + "[orgPath]", + "[orgPath]", + mavenCompatible = true, + bootOnly = true, + ) ) repoFileContains( """|[repositories] | id: https://repo1.maven.org, [orgPath], bootOnly""".stripMargin, Repository - .Ivy("id", new URL("https://repo1.maven.org"), "[orgPath]", "[orgPath]", false, true) + .Ivy( + "id", + new URL("https://repo1.maven.org"), + "[orgPath]", + "[orgPath]", + mavenCompatible = false, + bootOnly = true, + ) ) repoFileContains( """|[repositories] | id: https://repo1.maven.org, [orgPath], [artPath]""".stripMargin, Repository - .Ivy("id", new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]", false, false) + .Ivy( + "id", + new URL("https://repo1.maven.org"), + "[orgPath]", + "[artPath]", + mavenCompatible = false, + ) ) repoFileContains( @@ -82,10 +127,8 @@ object ConfigurationParserTest extends verify.BasicTestSuite { new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]", - false, - false, - true, - false + mavenCompatible = false, + descriptorOptional = true, ) ) @@ -97,10 +140,9 @@ object ConfigurationParserTest extends verify.BasicTestSuite { new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]", - false, - false, - true, - true + mavenCompatible = false, + descriptorOptional = true, + skipConsistencyCheck = true, ) ) @@ -112,10 +154,9 @@ object ConfigurationParserTest extends verify.BasicTestSuite { new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]", - false, - false, - true, - true + mavenCompatible = false, + descriptorOptional = true, + skipConsistencyCheck = true, ) ) @@ -127,10 +168,10 @@ object ConfigurationParserTest extends verify.BasicTestSuite { new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]", - true, - true, - true, - true + mavenCompatible = true, + bootOnly = true, + descriptorOptional = true, + skipConsistencyCheck = true, ) ) @@ -138,19 +179,53 @@ object ConfigurationParserTest extends verify.BasicTestSuite { """|[repositories] | id: https://repo1.maven.org, [orgPath], [artPath], bootOnly""".stripMargin, Repository - .Ivy("id", new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]", false, true) + .Ivy( + "id", + new URL("https://repo1.maven.org"), + "[orgPath]", + "[artPath]", + mavenCompatible = false, + bootOnly = true, + ) ) repoFileContains( """|[repositories] | id: https://repo1.maven.org, [orgPath], [artPath], bootOnly, mavenCompatible""".stripMargin, - Repository.Ivy("id", new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]", true, true) + Repository.Ivy( + "id", + new URL("https://repo1.maven.org"), + "[orgPath]", + "[artPath]", + mavenCompatible = true, + bootOnly = true, + ) ) repoFileContains( """|[repositories] | id: https://repo1.maven.org, [orgPath], [artPath], mavenCompatible, bootOnly""".stripMargin, - Repository.Ivy("id", new URL("https://repo1.maven.org"), "[orgPath]", "[artPath]", true, true) + Repository.Ivy( + "id", + new URL("https://repo1.maven.org"), + "[orgPath]", + "[artPath]", + mavenCompatible = true, + bootOnly = true, + ) + ) + + repoFileContains( + """|[repositories] + | id: https://repo1.maven.org, [orgPath], [artPath], mavenCompatible, bootOnlyZero""".stripMargin, + Repository.Ivy( + "id", + new URL("https://repo1.maven.org"), + "[orgPath]", + "[artPath]", + mavenCompatible = true, + bootOnlyZero = true, + ) ) repoFileContains(