Merge pull request #302 from eed3si9n/wip/plugins

bump plugins
This commit is contained in:
eugene yokota 2019-04-30 00:11:37 -04:00 committed by GitHub
commit 984de6fe72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 561 additions and 341 deletions

View File

@ -1,3 +1,4 @@
version = 2.0.0-RC6
maxColumn = 100
project.git = true
project.excludeFilters = [ /sbt-test/, /input_sources/, /contraband-scala/ ]
@ -8,3 +9,13 @@ docstrings = JavaDoc
# This also seems more idiomatic to include whitespace in import x.{ yyy }
spaces.inImportCurlyBraces = true
# This is more idiomatic Scala.
# http://docs.scala-lang.org/style/indentation.html#methods-with-numerous-arguments
align.openParenCallSite = false
align.openParenDefnSite = false
# For better code clarity
danglingParentheses = true
trailingCommas = preserve

View File

@ -42,7 +42,7 @@ install:
script: sbt -Dfile.encoding=UTF8
++$TRAVIS_SCALA_VERSION!
mimaReportBinaryIssues
scalafmt::test test:scalafmt::test sbt:scalafmt::test
scalafmtCheckAll
whitesourceCheckPolicies
test
scriptedIvy

View File

@ -29,6 +29,8 @@ def commonSettings: Seq[Setting[_]] = Def.settings(
}
},
inCompileAndTest(scalacOptions in console --= Vector("-Ywarn-unused-import", "-Ywarn-unused", "-Xlint")),
scalafmtOnCompile := true,
Test / scalafmtOnCompile := true,
publishArtifact in Compile := true,
publishArtifact in Test := false,
parallelExecution in Test := false
@ -57,7 +59,6 @@ lazy val lmRoot = (project in file("."))
Some(ScmInfo(url(s"https://github.com/$slug"), s"git@github.com:$slug.git"))
},
bintrayPackage := "librarymanagement",
scalafmtOnCompile in Sbt := false,
git.baseVersion := "1.3.0",
version := {
val v = version.value

View File

@ -5,9 +5,11 @@ import sbt.librarymanagement._
abstract class AbstractEngineSpec extends UnitSpec {
def cleanCache(): Unit
def module(moduleId: ModuleID,
def module(
moduleId: ModuleID,
deps: Vector[ModuleID],
scalaFullVersion: Option[String]): ModuleDescriptor
scalaFullVersion: Option[String]
): ModuleDescriptor
def updateEither(module: ModuleDescriptor): Either[UnresolvedWarning, UpdateReport]

View File

@ -19,7 +19,8 @@ private[librarymanagement] abstract class SemSelAndChunkFunctions {
// from and to can not have an operator.
if (hasOperator(fromStr) || hasOperator(toStr)) {
throw new IllegalArgumentException(
s"Invalid ' - ' range, both side of comparators can not have an operator: $fromStr - $toStr")
s"Invalid ' - ' range, both side of comparators can not have an operator: $fromStr - $toStr"
)
}
val from = SemComparator(fromStr)
val to = SemComparator(toStr)
@ -33,7 +34,8 @@ private[librarymanagement] abstract class SemSelAndChunkFunctions {
(comparatorsBefore ++ comparatorsAfter)
case _ =>
throw new IllegalArgumentException(
s"Invalid ' - ' range position, both side of versions must be specified: $andClauseToken")
s"Invalid ' - ' range position, both side of versions must be specified: $andClauseToken"
)
}
}
SemSelAndChunk(comparators.flatMap(_.expandWildcard))
@ -165,7 +167,8 @@ private[librarymanagement] abstract class SemComparatorFunctions {
if (hasXrangeSelector) {
if (tags.nonEmpty)
throw new IllegalArgumentException(
s"Pre-release version requires major, minor, patch versions to be specified: $comparator")
s"Pre-release version requires major, minor, patch versions to be specified: $comparator"
)
val numbers = Seq(major, minor, patch).takeWhile {
case Some(str) => str.matches("\\d+")
case None => false
@ -180,7 +183,8 @@ private[librarymanagement] abstract class SemComparatorFunctions {
} else {
if (tags.nonEmpty && (major.isEmpty || minor.isEmpty || patch.isEmpty))
throw new IllegalArgumentException(
s"Pre-release version requires major, minor, patch versions to be specified: $comparator")
s"Pre-release version requires major, minor, patch versions to be specified: $comparator"
)
val operator = opStr match {
case Some("<") => Lt
case Some("<=") => Lte

View File

@ -90,12 +90,14 @@ private[librarymanagement] abstract class ConfigurationExtra {
def describedAs(newDescription: String) =
Configuration.of(id, name, newDescription, isPublic, extendsConfigs, transitive)
def extend(configs: Configuration*) =
Configuration.of(id,
Configuration.of(
id,
name,
description,
isPublic,
configs.toVector ++ extendsConfigs,
transitive)
transitive
)
def notTransitive = intransitive
def intransitive = Configuration.of(id, name, description, isPublic, extendsConfigs, false)
def hide = Configuration.of(id, name, description, false, extendsConfigs, transitive)
@ -109,7 +111,8 @@ private[sbt] object ConfigurationMacro {
val enclosingValName = definingValName(
c,
methodName =>
s"""$methodName must be directly assigned to a val, such as `val Tooling = $methodName("tooling")`.""")
s"""$methodName must be directly assigned to a val, such as `val Tooling = $methodName("tooling")`."""
)
if (enclosingValName.head.isLower) {
c.error(c.enclosingPosition, "configuration id must be capitalized")
}

View File

@ -10,8 +10,10 @@ trait ConfigurationFormats {
self: sbt.librarymanagement.ConfigurationFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val ConfigurationFormat: JsonFormat[sbt.librarymanagement.Configuration] =
new JsonFormat[sbt.librarymanagement.Configuration] {
override def read[J](jsOpt: Option[J],
unbuilder: Unbuilder[J]): sbt.librarymanagement.Configuration = {
override def read[J](
jsOpt: Option[J],
unbuilder: Unbuilder[J]
): sbt.librarymanagement.Configuration = {
jsOpt match {
case Some(js) =>
unbuilder.beginObject(js)
@ -23,12 +25,14 @@ trait ConfigurationFormats {
unbuilder.readField[Vector[sbt.librarymanagement.Configuration]]("extendsConfigs")
val transitive = unbuilder.readField[Boolean]("transitive")
unbuilder.endObject()
new sbt.librarymanagement.Configuration(id,
new sbt.librarymanagement.Configuration(
id,
name,
description,
isPublic,
extendsConfigs,
transitive)
transitive
)
case None =>
deserializationError("Expected JsObject but found None")
}

View File

@ -175,8 +175,10 @@ object Full {
trait DisabledFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val DisabledFormat: JsonFormat[sbt.librarymanagement.Disabled] =
new JsonFormat[sbt.librarymanagement.Disabled] {
override def read[J](jsOpt: Option[J],
unbuilder: Unbuilder[J]): sbt.librarymanagement.Disabled = {
override def read[J](
jsOpt: Option[J],
unbuilder: Unbuilder[J]
): sbt.librarymanagement.Disabled = {
jsOpt match {
case Some(js) =>
unbuilder.beginObject(js)
@ -196,8 +198,10 @@ trait DisabledFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val DisabledObjectFormat: JsonFormat[sbt.librarymanagement.Disabled.type] =
new JsonFormat[sbt.librarymanagement.Disabled.type] {
override def read[J](jsOpt: Option[J],
unbuilder: Unbuilder[J]): sbt.librarymanagement.Disabled.type = {
override def read[J](
jsOpt: Option[J],
unbuilder: Unbuilder[J]
): sbt.librarymanagement.Disabled.type = {
jsOpt match {
case Some(js) =>
unbuilder.beginObject(js)
@ -219,8 +223,10 @@ trait DisabledFormats { self: sjsonnew.BasicJsonProtocol =>
trait BinaryFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val BinaryFormat: JsonFormat[sbt.librarymanagement.Binary] =
new JsonFormat[sbt.librarymanagement.Binary] {
override def read[J](jsOpt: Option[J],
unbuilder: Unbuilder[J]): sbt.librarymanagement.Binary = {
override def read[J](
jsOpt: Option[J],
unbuilder: Unbuilder[J]
): sbt.librarymanagement.Binary = {
jsOpt match {
case Some(js) =>
unbuilder.beginObject(js)
@ -244,8 +250,10 @@ trait BinaryFormats { self: sjsonnew.BasicJsonProtocol =>
trait ConstantFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val ConstantFormat: JsonFormat[sbt.librarymanagement.Constant] =
new JsonFormat[sbt.librarymanagement.Constant] {
override def read[J](jsOpt: Option[J],
unbuilder: Unbuilder[J]): sbt.librarymanagement.Constant = {
override def read[J](
jsOpt: Option[J],
unbuilder: Unbuilder[J]
): sbt.librarymanagement.Constant = {
jsOpt match {
case Some(js) =>
unbuilder.beginObject(js)
@ -267,8 +275,10 @@ trait ConstantFormats { self: sjsonnew.BasicJsonProtocol =>
trait PatchFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val PatchFormat: JsonFormat[sbt.librarymanagement.Patch] =
new JsonFormat[sbt.librarymanagement.Patch] {
override def read[J](jsOpt: Option[J],
unbuilder: Unbuilder[J]): sbt.librarymanagement.Patch = {
override def read[J](
jsOpt: Option[J],
unbuilder: Unbuilder[J]
): sbt.librarymanagement.Patch = {
jsOpt match {
case Some(js) =>
unbuilder.beginObject(js)
@ -290,8 +300,10 @@ trait PatchFormats { self: sjsonnew.BasicJsonProtocol =>
trait FullFormats { self: sjsonnew.BasicJsonProtocol =>
implicit lazy val FullFormat: JsonFormat[sbt.librarymanagement.Full] =
new JsonFormat[sbt.librarymanagement.Full] {
override def read[J](jsOpt: Option[J],
unbuilder: Unbuilder[J]): sbt.librarymanagement.Full = {
override def read[J](
jsOpt: Option[J],
unbuilder: Unbuilder[J]
): sbt.librarymanagement.Full = {
jsOpt match {
case Some(js) =>
unbuilder.beginObject(js)
@ -320,11 +332,13 @@ trait CrossVersionFormats {
with sbt.librarymanagement.PatchFormats
with sbt.librarymanagement.FullFormats =>
implicit lazy val CrossVersionFormat: JsonFormat[sbt.librarymanagement.CrossVersion] =
flatUnionFormat6[sbt.librarymanagement.CrossVersion,
flatUnionFormat6[
sbt.librarymanagement.CrossVersion,
sbt.librarymanagement.Disabled,
sbt.librarymanagement.Disabled.type,
sbt.librarymanagement.Binary,
sbt.librarymanagement.Constant,
sbt.librarymanagement.Patch,
sbt.librarymanagement.Full]("type")
sbt.librarymanagement.Full
]("type")
}

View File

@ -30,9 +30,11 @@ class DependencyResolution private[sbt] (lmEngine: DependencyResolutionInterface
* @param configurations The configurations that this module has.
* @return A `ModuleDescriptor` describing a subproject and its dependencies.
*/
def moduleDescriptor(moduleId: ModuleID,
def moduleDescriptor(
moduleId: ModuleID,
directDependencies: Vector[ModuleID],
scalaModuleInfo: Option[ScalaModuleInfo]): ModuleDescriptor = {
scalaModuleInfo: Option[ScalaModuleInfo]
): ModuleDescriptor = {
val moduleSetting = ModuleDescriptorConfiguration(moduleId, ModuleInfo(moduleId.name))
.withScalaModuleInfo(scalaModuleInfo)
.withDependencies(directDependencies)
@ -49,10 +51,12 @@ class DependencyResolution private[sbt] (lmEngine: DependencyResolutionInterface
* @return The result, either an unresolved warning or an update report. Note that this
* update report will or will not be successful depending on the `missingOk` option.
*/
def update(module: ModuleDescriptor,
def update(
module: ModuleDescriptor,
configuration: UpdateConfiguration,
uwconfig: UnresolvedWarningConfiguration,
log: Logger): Either[UnresolvedWarning, UpdateReport] =
log: Logger
): Either[UnresolvedWarning, UpdateReport] =
lmEngine.update(module, configuration, uwconfig, log)
/**
@ -71,8 +75,10 @@ class DependencyResolution private[sbt] (lmEngine: DependencyResolutionInterface
* @param scalaModuleInfo The information about the Scala verson used, if any.
* @return A `ModuleDescriptor` that depends on `dependencyId`.
*/
def wrapDependencyInModule(dependencyId: ModuleID,
scalaModuleInfo: Option[ScalaModuleInfo]): ModuleDescriptor = {
def wrapDependencyInModule(
dependencyId: ModuleID,
scalaModuleInfo: Option[ScalaModuleInfo]
): ModuleDescriptor = {
val sha1 = Hash.toHex(Hash(dependencyId.name))
val dummyID = ModuleID(sbtOrgTemp, modulePrefixTemp + sha1, dependencyId.revision)
.withConfigurations(dependencyId.configurations)
@ -88,10 +94,12 @@ class DependencyResolution private[sbt] (lmEngine: DependencyResolutionInterface
* @param log The logger.
* @return The result, either an unresolved warning or a sequence of files.
*/
def retrieve(dependencyId: ModuleID,
def retrieve(
dependencyId: ModuleID,
scalaModuleInfo: Option[ScalaModuleInfo],
retrieveDirectory: File,
log: Logger): Either[UnresolvedWarning, Vector[File]] =
log: Logger
): Either[UnresolvedWarning, Vector[File]] =
retrieve(wrapDependencyInModule(dependencyId, scalaModuleInfo), retrieveDirectory, log)
/**
@ -102,9 +110,11 @@ class DependencyResolution private[sbt] (lmEngine: DependencyResolutionInterface
* @param log The logger.
* @return The result, either an unresolved warning or a sequence of files.
*/
def retrieve(module: ModuleDescriptor,
def retrieve(
module: ModuleDescriptor,
retrieveDirectory: File,
log: Logger): Either[UnresolvedWarning, Vector[File]] = {
log: Logger
): Either[UnresolvedWarning, Vector[File]] = {
// Using the default artifact type filter here, so sources and docs are excluded.
val retrieveConfiguration = RetrieveConfiguration()
.withRetrieveDirectory(retrieveDirectory)

View File

@ -26,10 +26,12 @@ trait DependencyResolutionInterface {
* @return The result, either an unresolved warning or an update report. Note that this
* update report will or will not be successful depending on the `missingOk` option.
*/
def update(module: ModuleDescriptor,
def update(
module: ModuleDescriptor,
configuration: UpdateConfiguration,
uwconfig: UnresolvedWarningConfiguration,
log: Logger): Either[UnresolvedWarning, UpdateReport]
log: Logger
): Either[UnresolvedWarning, UpdateReport]
}
/**

View File

@ -35,9 +35,11 @@ class Publisher private[sbt] (publisherEngine: PublisherInterface) {
* @param log The logger.
* @return The `File` containing the POM descriptor.
*/
def makePomFile(module: ModuleDescriptor,
def makePomFile(
module: ModuleDescriptor,
configuration: MakePomConfiguration,
log: Logger): File =
log: Logger
): File =
publisherEngine.makePomFile(module, configuration, log)
}

View File

@ -169,8 +169,10 @@ private[librarymanagement] abstract class ResolverFunctions {
* Add the local Ivy repository to the user repositories.
* If `mavenCentral` is true, add the Maven Central repository.
*/
def combineDefaultResolvers(userResolvers: Vector[Resolver],
mavenCentral: Boolean): Vector[Resolver] =
def combineDefaultResolvers(
userResolvers: Vector[Resolver],
mavenCentral: Boolean
): Vector[Resolver] =
combineDefaultResolvers(userResolvers, jcenter = false, mavenCentral)
/**

View File

@ -14,12 +14,14 @@ final class RichUpdateReport(report: UpdateReport) {
val stamps = files
.map(
f =>
(f,
(
f,
// TODO: The list of files may also contain some odd files that do not actually exist like:
// "./target/ivyhome/resolution-cache/com.example/foo/0.4.0/resolved.xml.xml".
// IO.getModifiedTimeOrZero() will just return zero, but the list of files should not contain such
// files to begin with, in principle.
IO.getModifiedTimeOrZero(f))
IO.getModifiedTimeOrZero(f)
)
)
.toMap
UpdateReport(report.cachedDescriptor, report.configurations, report.stats, stamps)

View File

@ -74,24 +74,32 @@ private[librarymanagement] abstract class ModuleReportExtra {
reportStr(
"extraAttributes",
if (extraAttributes.isEmpty) None
else { Some(extraAttributes.toString) }
else {
Some(extraAttributes.toString)
}
) +
reportStr("isDefault", isDefault map { _.toString }) +
reportStr("branch", branch) +
reportStr(
"configurations",
if (configurations.isEmpty) None
else { Some(configurations.mkString(", ")) }
else {
Some(configurations.mkString(", "))
}
) +
reportStr(
"licenses",
if (licenses.isEmpty) None
else { Some(licenses.mkString(", ")) }
else {
Some(licenses.mkString(", "))
}
) +
reportStr(
"callers",
if (callers.isEmpty) None
else { Some(callers.mkString(", ")) }
else {
Some(callers.mkString(", "))
}
)
private[sbt] def reportStr(key: String, value: Option[String]): String =
value map { x =>

View File

@ -11,11 +11,14 @@ object ResolverTest extends UnitSpec {
val patsExpected = Vector("http://foo.com/test/[orgPath]")
val patterns = Resolver
.url("test", new URL("http://foo.com/test"))(
Patterns(pats,
Patterns(
pats,
pats,
isMavenCompatible = false,
descriptorOptional = true,
skipConsistencyCheck = true))
skipConsistencyCheck = true
)
)
.patterns
patterns.ivyPatterns shouldBe patsExpected

View File

@ -30,7 +30,9 @@ class ComponentManager(
def files(id: String)(ifMissing: IfMissing): Iterable[File] = {
def fromGlobal =
lockGlobalCache {
try { update(id); getOrElse(createAndCache) } catch {
try {
update(id); getOrElse(createAndCache)
} catch {
case _: NotInCache => createAndCache
}
}
@ -100,7 +102,11 @@ object ComponentManager {
lazy val (version, timestamp) = {
val properties = new java.util.Properties
val propertiesStream = versionResource.openStream
try { properties.load(propertiesStream) } finally { propertiesStream.close() }
try {
properties.load(propertiesStream)
} finally {
propertiesStream.close()
}
(properties.getProperty("version"), properties.getProperty("timestamp"))
}
lazy val stampedVersion = version + "_" + timestamp

View File

@ -246,9 +246,11 @@ private[sbt] object ConvertResolver {
def managedChecksumsEnabled: Boolean
import sbt.io.syntax._
private def downloadChecksum(resource: Resource,
private def downloadChecksum(
resource: Resource,
targetChecksumFile: File,
algorithm: String): Boolean = {
algorithm: String
): Boolean = {
if (!ChecksumHelper.isKnownAlgorithm(algorithm))
throw new IllegalArgumentException(s"Unknown checksum algorithm: $algorithm")

View File

@ -178,8 +178,9 @@ private[sbt] class FakeResolver(private var name: String, cacheDir: File, module
val artifact =
for {
artifacts <- modules get ((moduleOrganisation, moduleName, moduleRevision))
artifact <- artifacts find (a =>
a.name == art.getName && a.tpe == art.getType && a.ext == art.getExt)
artifact <- artifacts find (
a => a.name == art.getName && a.tpe == art.getType && a.ext == art.getExt
)
} yield new ArtifactOrigin(art, /* isLocal = */ true, artifact.file.toURI.toURL.toString)
artifact.orNull

View File

@ -73,7 +73,11 @@ final class IvySbt(
IvySbt.synchronized {
val originalLogger = Message.getDefaultLogger
Message.setDefaultLogger(logger)
try { f } finally { Message.setDefaultLogger(originalLogger) }
try {
f
} finally {
Message.setDefaultLogger(originalLogger)
}
}
// Ivy is not thread-safe nor can the cache be used concurrently.
// If provided a GlobalLock, we can use that to ensure safe access to the cache.
@ -207,7 +211,9 @@ final class IvySbt(
ivyint.ErrorMessageAuthenticator.install()
ivy.pushContext()
ivy.getLoggerEngine.pushLogger(log)
try { f(ivy) } finally {
try {
f(ivy)
} finally {
ivy.getLoggerEngine.popLogger()
ivy.popContext()
}
@ -275,7 +281,8 @@ final class IvySbt(
IvySbt.setConflictManager(moduleID, conflictManager, ivy.getSettings)
val defaultConf = defaultConfiguration getOrElse Configuration.of(
"Default",
ModuleDescriptor.DEFAULT_CONFIGURATION)
ModuleDescriptor.DEFAULT_CONFIGURATION
)
log.debug(
s"Using inline dependencies specified in Scala${(if (ivyXML.isEmpty) "" else " and XML")}."
)
@ -729,9 +736,11 @@ private[sbt] object IvySbt {
allConfigurations: Vector[ConfigRef]
): MDArtifact = {
val artifact = new MDArtifact(moduleID, a.name, a.`type`, a.extension, null, extra(a, false))
copyConfigurations(a,
copyConfigurations(
a,
(ref: ConfigRef) => { artifact.addConfiguration(ref.name) },
allConfigurations)
allConfigurations
)
artifact
}
def getExtraAttributes(revID: ExtendableItem): Map[String, String] = {
@ -995,7 +1004,8 @@ private[sbt] object IvySbt {
): Unit = excludes.foreach(exclude => addExclude(moduleID, scalaModuleInfo)(exclude))
def addExclude(moduleID: DefaultModuleDescriptor, scalaModuleInfo: Option[ScalaModuleInfo])(
exclude0: ExclusionRule): Unit = {
exclude0: ExclusionRule
): Unit = {
// this adds _2.11 postfix
val exclude = CrossVersion.substituteCross(exclude0, scalaModuleInfo)
val confs =

View File

@ -152,7 +152,11 @@ object IvyActions {
): T = {
val previous = resolver.getChecksumAlgorithms
resolver.setChecksums(checksums mkString ",")
try { act } finally { resolver.setChecksums(previous mkString ",") }
try {
act
} finally {
resolver.setChecksums(previous mkString ",")
}
}
private def crossVersionMap(moduleSettings: ModuleSettings): Option[String => String] =
moduleSettings match {
@ -367,12 +371,14 @@ object IvyActions {
resolveOptions.setTransitive(false)
resolveOptions.setCheckIfChanged(false)
}
resolver.customResolve(descriptor,
resolver.customResolve(
descriptor,
missingOk,
updateConfiguration.logicalClock,
resolveOptions,
cache,
log)
log
)
}
private def retrieve(
@ -496,7 +502,11 @@ object IvyActions {
resolver.commitPublishTransaction()
} catch {
case e: Throwable =>
try { resolver.abortPublishTransaction() } finally { throw e }
try {
resolver.abortPublishTransaction()
} finally {
throw e
}
}
}
}

View File

@ -58,7 +58,9 @@ class IvyCache(val ivyHome: Option[File]) {
/** Clears the cache of the jar for the given ID.*/
def clearCachedJar(id: ModuleID, lock: Option[xsbti.GlobalLock], log: Logger): Unit = {
try { withCachedJar(id, lock, log)(_.delete); () } catch {
try {
withCachedJar(id, lock, log)(_.delete); ()
} catch {
case e: Exception => log.debug("Error cleaning cached jar: " + e.toString)
}
}

View File

@ -232,7 +232,8 @@ class MakePom(val log: Logger) {
if (k == PomExtraDependencyAttributes.ExtraAttributesKey) xmlSpacePreserve
else scala.xml.Null
<properties> {
for ((key, value) <- extra) yield (<x>{ value }</x>).copy(label = key, attributes = _extraAttributes(key))
for ((key, value) <- extra)
yield (<x>{value}</x>).copy(label = key, attributes = _extraAttributes(key))
} </properties>
}
@ -244,18 +245,34 @@ class MakePom(val log: Logger) {
def xmlSpacePreserve = new PrefixedAttribute("xml", "space", "preserve", scala.xml.Null)
def description(d: String) =
if ((d eq null) || d.isEmpty) NodeSeq.Empty else <description>{ d }</description>
if ((d eq null) || d.isEmpty) NodeSeq.Empty
else
<description>{
d
}</description>
def licenses(ls: Array[License]) =
if (ls == null || ls.isEmpty) NodeSeq.Empty else <licenses>{ ls.map(license) }</licenses>
if (ls == null || ls.isEmpty) NodeSeq.Empty
else
<licenses>{
ls.map(license)
}</licenses>
def license(l: License) =
<license>
<name>{l.getName}</name>
<url>{l.getUrl}</url>
<distribution>repo</distribution>
</license>
def homePage(homePage: String) = if (homePage eq null) NodeSeq.Empty else <url>{ homePage }</url>
def homePage(homePage: String) =
if (homePage eq null) NodeSeq.Empty
else
<url>{
homePage
}</url>
def revision(version: String) =
if (version ne null) <version>{ version }</version> else NodeSeq.Empty
if (version ne null) <version>{
version
}</version>
else NodeSeq.Empty
def packaging(module: ModuleDescriptor) =
module.getAllArtifacts match {
case Array() => "pom"
@ -286,7 +303,9 @@ class MakePom(val log: Logger) {
NodeSeq.Empty
else
<dependencies>
{ dependencies.map(makeDependency(_, includeTypes, excludes)) }
{
dependencies.map(makeDependency(_, includeTypes, excludes))
}
</dependencies>
@deprecated("Use `makeDependency` variant which takes excludes", "0.13.9")
@ -426,7 +445,9 @@ class MakePom(val log: Logger) {
val excl = dependency.getExcludeRules(dependency.getModuleConfigurations) ++ excludes
val (warns, excls) = IvyUtil.separate(excl.map(makeExclusion))
if (warns.nonEmpty) log.warn(warns.mkString(IO.Newline))
if (excls.nonEmpty) <exclusions>{ excls }</exclusions>
if (excls.nonEmpty) <exclusions>{
excls
}</exclusions>
else NodeSeq.Empty
}
def makeExclusion(exclRule: ExcludeRule): Either[String, NodeSeq] = {
@ -466,7 +487,10 @@ class MakePom(val log: Logger) {
}
val repositoryElements = mavenRepositories.filter(filterRepositories).map(mavenRepository)
if (repositoryElements.isEmpty) repositoryElements
else <repositories>{ repositoryElements }</repositories>
else
<repositories>{
repositoryElements
}</repositories>
}
def allResolvers(settings: IvySettings): Seq[DependencyResolver] =
flatten(castResolvers(settings.getResolvers)).distinct

View File

@ -188,11 +188,13 @@ private[sbt] class CachedResolutionResolveCache {
val (pathOrg, pathName, pathRevision, pathScalaVersion, pathSbtVersion) = md match {
case x: ArtificialModuleDescriptor =>
val tmrid = x.targetModuleRevisionId
(tmrid.getOrganisation,
(
tmrid.getOrganisation,
tmrid.getName,
tmrid.getRevision + "_" + mrid.getName,
scalaVersion(tmrid),
sbtVersion(tmrid))
sbtVersion(tmrid)
)
case _ =>
(mrid.getOrganisation, mrid.getName, mrid.getRevision, scalaVersion(mrid), sbtVersion(mrid))
}
@ -328,7 +330,9 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine {
val ivy = makeInstance
ivy.pushContext()
ivy.getLoggerEngine.pushLogger(log)
try { f(ivy) } finally {
try {
f(ivy)
} finally {
ivy.getLoggerEngine.popLogger()
ivy.popContext()
}
@ -336,7 +340,11 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine {
def withDefaultLogger[A](log: MessageLogger)(f: => A): A = {
val originalLogger = Message.getDefaultLogger
Message.setDefaultLogger(log)
try { f } finally { Message.setDefaultLogger(originalLogger) }
try {
f
} finally {
Message.setDefaultLogger(originalLogger)
}
}
/**
@ -488,8 +496,10 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine {
case (failed, paths) =>
if (paths.isEmpty) (failed, paths)
else
(failed,
List(IvyRetrieve.toModuleID(md0.getResolvedModuleRevisionId)) ::: paths.toList.tail)
(
failed,
List(IvyRetrieve.toModuleID(md0.getResolvedModuleRevisionId)) ::: paths.toList.tail
)
}
}
new ResolveException(messages, failed, ListMap(failedPaths: _*))
@ -577,8 +587,9 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine {
((organization, name), xs)
}: _*)
// this returns a List of Lists of (org, name). should be deterministic
def detectLoops(allModules: Map[(String, String), Vector[OrganizationArtifactReport]])
: List[List[(String, String)]] = {
def detectLoops(
allModules: Map[(String, String), Vector[OrganizationArtifactReport]]
): List[List[(String, String)]] = {
val loopSets: mutable.Set[Set[(String, String)]] = mutable.Set.empty
val loopLists: mutable.ListBuffer[List[(String, String)]] = mutable.ListBuffer.empty
def testLoop(
@ -949,8 +960,9 @@ private[sbt] trait CachedResolutionResolveEngine extends ResolveEngine {
val configurations0: Vector[ConfigurationReport] = ur.configurations.toVector
// This is how md looks from md0 via dd's mapping.
val remappedConfigs0: Map[String, Vector[String]] = Map(rootModuleConfs map { conf0 =>
val remapped
: Vector[String] = dd.getDependencyConfigurations(conf0.getName).toVector flatMap { conf =>
val remapped: Vector[String] = dd
.getDependencyConfigurations(conf0.getName)
.toVector flatMap { conf =>
node.getRealConfs(conf).toVector
}
conf0.getName -> remapped

View File

@ -52,12 +52,16 @@ class GigahorseUrlHandler(http: OkHttpClient) extends AbstractURLHandler {
if (checkStatusCode(url, response)) {
val bodyCharset =
BasicURLHandler.getCharSetFromContentType(
Option(response.body().contentType()).map(_.toString).orNull)
Option(response.body().contentType()).map(_.toString).orNull
)
Some(
new SbtUrlInfo(true,
new SbtUrlInfo(
true,
response.body().contentLength(),
lastModifiedTimestamp(response),
bodyCharset))
bodyCharset
)
)
} else None
//
// Commented out for now - can potentially be used for non HTTP urls
@ -75,7 +79,8 @@ class GigahorseUrlHandler(http: OkHttpClient) extends AbstractURLHandler {
Message.warn("Host " + e.getMessage + " not found. url=" + url)
Message.info(
"You probably access the destination server through "
+ "a proxy server that is not well configured.")
+ "a proxy server that is not well configured."
)
None
case e: IOException =>
Message.error("Server access Error: " + e.getMessage + " url=" + url)
@ -106,7 +111,8 @@ class GigahorseUrlHandler(http: OkHttpClient) extends AbstractURLHandler {
if (!checkStatusCode(url, response)) {
throw new IOException(
"The HTTP response code for " + url + " did not indicate a success."
+ " See log for more detail.")
+ " See log for more detail."
)
}
response
} catch {
@ -145,7 +151,8 @@ class GigahorseUrlHandler(http: OkHttpClient) extends AbstractURLHandler {
IO.delete(dest)
throw new IOException(
"Downloaded file size doesn't match expected Content Length for " + url
+ ". Please retry.")
+ ". Please retry."
)
}
val lastModified = lastModifiedTimestamp(response)
@ -198,11 +205,12 @@ class GigahorseUrlHandler(http: OkHttpClient) extends AbstractURLHandler {
object GigahorseUrlHandler {
// This is requires to access the constructor of URLInfo.
private[sbt] class SbtUrlInfo(available: Boolean,
private[sbt] class SbtUrlInfo(
available: Boolean,
contentLength: Long,
lastModified: Long,
bodyCharset: String)
extends URLInfo(available, contentLength, lastModified, bodyCharset) {
bodyCharset: String
) extends URLInfo(available, contentLength, lastModified, bodyCharset) {
def this(available: Boolean, contentLength: Long, lastModified: Long) = {
this(available, contentLength, lastModified, null)
}
@ -220,7 +228,8 @@ object GigahorseUrlHandler {
Message.warn("Your proxy requires authentication.")
} else if (status == 401) {
Message.warn(
"CLIENT ERROR: 401 Unauthorized. Check your resolvers username and password.")
"CLIENT ERROR: 401 Unauthorized. Check your resolvers username and password."
)
} else if (String.valueOf(status).startsWith("4")) {
Message.verbose("CLIENT ERROR: " + response.message() + " url=" + url)
} else if (String.valueOf(status).startsWith("5")) {

View File

@ -14,9 +14,11 @@ import org.apache.ivy.util.filter.Filter
import scala.concurrent.duration.Duration
import scala.concurrent.{ Await, ExecutionContext, Future }
private[ivyint] case class DownloadResult(dep: IvyNode,
private[ivyint] case class DownloadResult(
dep: IvyNode,
report: DownloadReport,
totalSizeDownloaded: Long)
totalSizeDownloaded: Long
)
object ParallelResolveEngine {
private lazy val resolveExecutionContext: ExecutionContext = {
@ -28,14 +30,17 @@ object ParallelResolveEngine {
}
/** Define an ivy [[ResolveEngine]] that resolves dependencies in parallel. */
private[sbt] class ParallelResolveEngine(settings: ResolveEngineSettings,
private[sbt] class ParallelResolveEngine(
settings: ResolveEngineSettings,
eventManager: EventManager,
sortEngine: SortEngine)
extends ResolveEngine(settings, eventManager, sortEngine) {
sortEngine: SortEngine
) extends ResolveEngine(settings, eventManager, sortEngine) {
override def downloadArtifacts(report: ResolveReport,
override def downloadArtifacts(
report: ResolveReport,
artifactFilter: Filter,
options: DownloadOptions): Unit = {
options: DownloadOptions
): Unit = {
import scala.collection.JavaConverters._
val start = System.currentTimeMillis
report.getArtifacts match {
@ -82,9 +87,11 @@ private[sbt] class ParallelResolveEngine(settings: ResolveEngineSettings,
*
* Return the report and the total downloaded size.
*/
private def downloadNodeArtifacts(dependency: IvyNode,
private def downloadNodeArtifacts(
dependency: IvyNode,
artifactFilter: Filter,
options: DownloadOptions): DownloadResult = {
options: DownloadOptions
): DownloadResult = {
val resolver = dependency.getModuleRevision.getArtifactResolver
val selectedArtifacts = dependency.getSelectedArtifacts(artifactFilter)

View File

@ -94,9 +94,11 @@ private[sbt] case class SbtChainResolver(
/** Implements the custom sbt chain resolution with support for snapshots and caching. */
private object CustomSbtResolution {
def getCached(dd: DependencyDescriptor,
def getCached(
dd: DependencyDescriptor,
data: ResolveData,
resolved0: Option[ResolvedModuleRevision]): Option[ResolvedModuleRevision] = {
resolved0: Option[ResolvedModuleRevision]
): Option[ResolvedModuleRevision] = {
resolved0.orElse {
val resolverName = getName
Message.verbose(s"$resolverName: Checking cache for: $dd")
@ -144,7 +146,8 @@ private[sbt] case class SbtChainResolver(
var currentlyResolved = resolved0
def performResolution(
resolver: DependencyResolver): Option[(ResolvedModuleRevision, DependencyResolver)] = {
resolver: DependencyResolver
): Option[(ResolvedModuleRevision, DependencyResolver)] = {
// Resolve all resolvers when the module is changing
val previouslyResolved = currentlyResolved
if (useLatest) data.setCurrentResolvedModuleRevision(null)
@ -152,8 +155,9 @@ private[sbt] case class SbtChainResolver(
currentlyResolved = Option(resolver.getDependency(descriptor, data))
if (currentlyResolved eq previouslyResolved) None
else if (useLatest) {
currentlyResolved.map(x =>
(reparseModuleDescriptor(descriptor, data, resolver, x), resolver))
currentlyResolved.map(
x => (reparseModuleDescriptor(descriptor, data, resolver, x), resolver)
)
} else currentlyResolved.map(x => (forcedRevision(x), resolver))
}
@ -179,9 +183,11 @@ private[sbt] case class SbtChainResolver(
}
private final val prefix = "Undefined resolution order"
def resolveLatest(foundRevisions: Seq[(ResolvedModuleRevision, DependencyResolver)],
def resolveLatest(
foundRevisions: Seq[(ResolvedModuleRevision, DependencyResolver)],
descriptor: DependencyDescriptor,
data: ResolveData): Option[ResolvedModuleRevision] = {
data: ResolveData
): Option[ResolvedModuleRevision] = {
val sortedRevisions = foundRevisions.sortBy {
case (rmr, resolver) =>
@ -220,13 +226,15 @@ private[sbt] case class SbtChainResolver(
if (resolvedModule.getId.getRevision.contains("SNAPSHOT")) {
Message.warn(
"Resolving a snapshot version. It's going to be slow unless you use `updateOptions := updateOptions.value.withLatestSnapshots(false)` options.")
"Resolving a snapshot version. It's going to be slow unless you use `updateOptions := updateOptions.value.withLatestSnapshots(false)` options."
)
val resolvers = sortedRevisions.map(_._2.getName)
sortedRevisions.foreach(h => {
val (module, resolver) = h
Message.info(
s"Out of ${sortedRevisions.size} candidates we found for ${module.getId} in ${resolvers
.mkString(" and ")}, we are choosing ${resolver}.")
.mkString(" and ")}, we are choosing ${resolver}."
)
})
} else {
Message.warn(s"Choosing $resolver for ${resolvedModule.getId}")

View File

@ -14,10 +14,12 @@ class IvyDependencyResolution private[sbt] (val ivySbt: IvySbt)
new Module(moduleSetting)
}
override def update(module: ModuleDescriptor,
override def update(
module: ModuleDescriptor,
configuration: UpdateConfiguration,
uwconfig: UnresolvedWarningConfiguration,
log: Logger): Either[UnresolvedWarning, UpdateReport] =
log: Logger
): Either[UnresolvedWarning, UpdateReport] =
IvyActions.updateEither(toModule(module), configuration, uwconfig, log)
private[sbt] def toModule(module: ModuleDescriptor): Module =

View File

@ -14,14 +14,18 @@ class IvyPublisher private[sbt] (val ivySbt: IvySbt) extends PublisherInterface
new Module(moduleSetting)
}
override def makePomFile(module: ModuleDescriptor,
override def makePomFile(
module: ModuleDescriptor,
configuration: MakePomConfiguration,
log: Logger): File =
log: Logger
): File =
IvyActions.makePomFile(toModule(module), configuration, log)
override def publish(module: ModuleDescriptor,
override def publish(
module: ModuleDescriptor,
configuration: PublishConfiguration,
log: Logger): Unit =
log: Logger
): Unit =
IvyActions.publish(toModule(module), configuration, log)
private[sbt] def toModule(module: ModuleDescriptor): Module =

View File

@ -4,9 +4,11 @@ import sbt.librarymanagement._
import sbt.librarymanagement.ivy._
trait BaseCachedResolutionSpec extends BaseIvySpecification {
override def module(moduleId: ModuleID,
override def module(
moduleId: ModuleID,
deps: Vector[ModuleID],
scalaFullVersion: Option[String]): ModuleDescriptor = {
scalaFullVersion: Option[String]
): ModuleDescriptor = {
val uo: UpdateOptions = UpdateOptions()
.withCachedResolution(true)
module(moduleId, deps, scalaFullVersion, uo, true)

View File

@ -24,17 +24,21 @@ trait BaseIvySpecification extends AbstractEngineSpec {
def configurations = Vector(Compile, Test, Runtime)
def module(moduleId: ModuleID,
def module(
moduleId: ModuleID,
deps: Vector[ModuleID],
scalaFullVersion: Option[String]): ModuleDescriptor = {
scalaFullVersion: Option[String]
): ModuleDescriptor = {
module(moduleId, deps, scalaFullVersion, UpdateOptions(), true)
}
def module(moduleId: ModuleID,
def module(
moduleId: ModuleID,
deps: Vector[ModuleID],
scalaFullVersion: Option[String],
uo: UpdateOptions = UpdateOptions(),
overrideScalaVersion: Boolean = true): IvySbt#Module = {
overrideScalaVersion: Boolean = true
): IvySbt#Module = {
val scalaModuleInfo = scalaFullVersion map { fv =>
ScalaModuleInfo(
scalaFullVersion = fv,
@ -71,8 +75,10 @@ trait BaseIvySpecification extends AbstractEngineSpec {
.withUpdateOptions(uo)
}
def makeUpdateConfiguration(offline: Boolean,
metadataDirectory: Option[File]): UpdateConfiguration = {
def makeUpdateConfiguration(
offline: Boolean,
metadataDirectory: Option[File]
): UpdateConfiguration = {
val retrieveConfig = RetrieveConfiguration()
.withRetrieveDirectory(currentManaged)
.withOutputPattern(Resolver.defaultRetrievePattern)
@ -108,8 +114,10 @@ trait BaseIvySpecification extends AbstractEngineSpec {
def ivyUpdate(module: ModuleDescriptor): UpdateReport =
update(module)
def mkPublishConfiguration(resolver: Resolver,
artifacts: Map[Artifact, File]): PublishConfiguration = {
def mkPublishConfiguration(
resolver: Resolver,
artifacts: Map[Artifact, File]
): PublishConfiguration = {
PublishConfiguration()
.withResolverName(resolver.name)
.withArtifacts(artifacts.toVector)

View File

@ -67,7 +67,9 @@ class ComponentManagerTest extends UnitSpec {
withManagerHome(ivyHome) { usingManager =>
checksum(usingManager.file(TestID)(Fail)) shouldBe hash
}
} finally { definingManager.clearCache(TestID) }
} finally {
definingManager.clearCache(TestID)
}
}
}
}
@ -82,7 +84,8 @@ class ComponentManagerTest extends UnitSpec {
private def createFile[T](manager: ComponentManager, id: String, name: String)(f: File => T): T =
createFiles(manager, id, name)(files => f(files.toList.head))
private def createFiles[T](manager: ComponentManager, id: String, names: String*)(
f: Seq[File] => T): T =
f: Seq[File] => T
): T =
withTemporaryDirectory { dir =>
val files = names.map(name => new File(dir, name))
files.foreach(writeRandomContent)
@ -113,7 +116,8 @@ class ComponentManagerTest extends UnitSpec {
val location = componentLocation(id)
if (location.exists)
throw new RuntimeException(
s"Cannot redefine component. ID: $id, files: ${files.mkString(",")}")
s"Cannot redefine component. ID: $id, files: ${files.mkString(",")}"
)
else {
IO.copy(files.map { f =>
f -> new java.io.File(location, f.getName)

View File

@ -51,14 +51,18 @@ class DMSerializationSpec extends UnitSpec {
}
lazy val updateReportExample =
UpdateReport(new File("./foo"),
UpdateReport(
new File("./foo"),
Vector(configurationReportExample),
UpdateStats(0, 0, 0, false),
Map(new File("./foo") -> 0))
Map(new File("./foo") -> 0)
)
lazy val configurationReportExample =
ConfigurationReport(ConfigRef("compile"),
ConfigurationReport(
ConfigRef("compile"),
Vector(moduleReportExample),
Vector(organizationArtifactReportExample))
Vector(organizationArtifactReportExample)
)
lazy val organizationArtifactReportExample =
OrganizationArtifactReport("org", "name", Vector(moduleReportExample))
lazy val moduleReportExample =

View File

@ -62,7 +62,8 @@ class EvictionWarningSpec extends BaseIvySpecification {
val m2 = "org.scala-sbt" % "util-logging_2.12" % "1.1.0"
assert(
EvictionWarningOptions
.defaultGuess((m1, Option(m2), Option(dummyScalaModuleInfo("2.12.4")))))
.defaultGuess((m1, Option(m2), Option(dummyScalaModuleInfo("2.12.4"))))
)
}
def akkaActor214 =

View File

@ -49,7 +49,9 @@ class FrozenModeSpec extends BaseIvySpecification {
val toExplicitResolve = module(defaultModuleId, explicitStoml, None, normalOptions)
val frozenResolution = update(toExplicitResolve, frozenConf)
assert(frozenResolution.isRight)
assert(frozenResolution.right.get.allModules.size == numberResolved,
s"The number of explicit modules in frozen mode should be equal than $numberResolved")
assert(
frozenResolution.right.get.allModules.size == numberResolved,
s"The number of explicit modules in frozen mode should be equal than $numberResolved"
)
}
}

View File

@ -61,19 +61,23 @@ class IvyRepoSpec extends BaseIvySpecification {
val clMod = {
val externalModules = Vector(dep)
// Note: need to extract ourModuleID so we can plug it in here, can't fish it back out of the IvySbt#Module (`m`)
GetClassifiersModule(ourModuleID,
GetClassifiersModule(
ourModuleID,
scalaModuleInfo,
externalModules,
Vector(Configurations.Compile),
attemptedClassifiers)
attemptedClassifiers
)
}
val artifactFilter = getArtifactTypeFilter(c.artifactFilter)
val gcm = GetClassifiersConfiguration(clMod,
val gcm = GetClassifiersConfiguration(
clMod,
Vector.empty,
c.withArtifactFilter(artifactFilter.invert),
srcTypes,
docTypes)
docTypes
)
val report2 =
lmEngine()

View File

@ -25,51 +25,81 @@ class ScalaOverrideTest extends UnitSpec {
}
"""OverrideScalaMediator
""" should "Override compiler version" in check(Organization, "2.11.8")(Organization,
""" should "Override compiler version" in check(Organization, "2.11.8")(
Organization,
CompilerID,
"2.11.9")
it should "Override library version" in check(Organization, "2.11.8")(Organization,
"2.11.9"
)
it should "Override library version" in check(Organization, "2.11.8")(
Organization,
LibraryID,
"2.11.8")
it should "Override reflect version" in check(Organization, "2.11.8")(Organization,
"2.11.8"
)
it should "Override reflect version" in check(Organization, "2.11.8")(
Organization,
ReflectID,
"2.11.7")
it should "Override actors version" in check(Organization, "2.11.8")(Organization,
"2.11.7"
)
it should "Override actors version" in check(Organization, "2.11.8")(
Organization,
ActorsID,
"2.11.6")
it should "Override scalap version" in check(Organization, "2.11.8")(Organization,
"2.11.6"
)
it should "Override scalap version" in check(Organization, "2.11.8")(
Organization,
ScalapID,
"2.11.5")
"2.11.5"
)
it should "Override default compiler organization" in check(OtherOrgID, "2.11.8")(Organization,
it should "Override default compiler organization" in check(OtherOrgID, "2.11.8")(
Organization,
CompilerID,
"2.11.9")
it should "Override default library organization" in check(OtherOrgID, "2.11.8")(Organization,
"2.11.9"
)
it should "Override default library organization" in check(OtherOrgID, "2.11.8")(
Organization,
LibraryID,
"2.11.8")
it should "Override default reflect organization" in check(OtherOrgID, "2.11.8")(Organization,
"2.11.8"
)
it should "Override default reflect organization" in check(OtherOrgID, "2.11.8")(
Organization,
ReflectID,
"2.11.7")
it should "Override default actors organization" in check(OtherOrgID, "2.11.8")(Organization,
"2.11.7"
)
it should "Override default actors organization" in check(OtherOrgID, "2.11.8")(
Organization,
ActorsID,
"2.11.6")
it should "Override default scalap organization" in check(OtherOrgID, "2.11.8")(Organization,
"2.11.6"
)
it should "Override default scalap organization" in check(OtherOrgID, "2.11.8")(
Organization,
ScalapID,
"2.11.5")
"2.11.5"
)
it should "Override custom compiler organization" in check(Organization, "2.11.8")(OtherOrgID,
it should "Override custom compiler organization" in check(Organization, "2.11.8")(
OtherOrgID,
CompilerID,
"2.11.9")
it should "Override custom library organization" in check(Organization, "2.11.8")(OtherOrgID,
"2.11.9"
)
it should "Override custom library organization" in check(Organization, "2.11.8")(
OtherOrgID,
LibraryID,
"2.11.8")
it should "Override custom reflect organization" in check(Organization, "2.11.8")(OtherOrgID,
"2.11.8"
)
it should "Override custom reflect organization" in check(Organization, "2.11.8")(
OtherOrgID,
ReflectID,
"2.11.7")
it should "Override custom actors organization" in check(Organization, "2.11.8")(OtherOrgID,
"2.11.7"
)
it should "Override custom actors organization" in check(Organization, "2.11.8")(
OtherOrgID,
ActorsID,
"2.11.6")
it should "Override custom scalap organization" in check(Organization, "2.11.8")(OtherOrgID,
"2.11.6"
)
it should "Override custom scalap organization" in check(Organization, "2.11.8")(
OtherOrgID,
ScalapID,
"2.11.5")
"2.11.5"
)
}

View File

@ -1,6 +1,6 @@
addSbtPlugin("org.scala-sbt" % "sbt-houserules" % "0.3.8")
addSbtPlugin("com.lucidchart" % "sbt-scalafmt" % "1.15")
addSbtPlugin("org.scala-sbt" % "sbt-houserules" % "0.3.9")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.0.0")
addSbtPlugin("org.scala-sbt" % "sbt-contraband" % "0.4.2")
addSbtPlugin("com.lightbend" % "sbt-whitesource" % "0.1.9")
addSbtPlugin("com.lightbend" % "sbt-whitesource" % "0.1.14")
scalacOptions += "-language:postfixOps"