mirror of https://github.com/sbt/sbt.git
Merge branch '0.13' of github.com:sbt/sbt into 0.13
This commit is contained in:
commit
3ea995225f
|
|
@ -26,6 +26,7 @@ env:
|
|||
- SCRIPTED_TEST="scripted source-dependencies/*2of3"
|
||||
- SCRIPTED_TEST="scripted source-dependencies/*3of3"
|
||||
- SCRIPTED_TEST="scripted tests/*"
|
||||
- SCRIPTED_TEST="scripted project-load/*"
|
||||
- SCRIPTED_TEST="safeUnitTests"
|
||||
- SCRIPTED_TEST="checkBuildScala211"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
[CONTRIBUTING]: CONTRIBUTING.md
|
||||
[Setup]: http://www.scala-sbt.org/release/docs/Getting-Started/Setup
|
||||
[FAQ]: http://www.scala-sbt.org/release/docs/faq
|
||||
[sbt-dev]: https://groups.google.com/d/forum/sbt-dev
|
||||
[sbt-dev]: https://groups.google.com/d/forum/sbt-dev
|
||||
[StackOverflow]: http://stackoverflow.com/tags/sbt
|
||||
[LICENSE]: LICENSE
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import java.io.File
|
|||
import org.apache.ivy.util.ChecksumHelper
|
||||
import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact }
|
||||
|
||||
private object ConvertResolver {
|
||||
private[sbt] object ConvertResolver {
|
||||
/**
|
||||
* This class contains all the reflective lookups used in the
|
||||
* checksum-friendly URL publishing shim.
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ final class IvySbt(val configuration: IvyConfiguration) {
|
|||
}
|
||||
}
|
||||
|
||||
private object IvySbt {
|
||||
private[sbt] object IvySbt {
|
||||
val DefaultIvyConfigFilename = "ivysettings.xml"
|
||||
val DefaultIvyFilename = "ivy.xml"
|
||||
val DefaultMavenFilename = "pom.xml"
|
||||
|
|
@ -273,219 +273,23 @@ private object IvySbt {
|
|||
mrid.getRevision endsWith "-SNAPSHOT"
|
||||
def resolverChain(name: String, resolvers: Seq[Resolver], localOnly: Boolean, settings: IvySettings, log: Logger): DependencyResolver =
|
||||
resolverChain(name, resolvers, localOnly, settings, UpdateOptions(), log)
|
||||
def resolverChain(name: String, resolvers: Seq[Resolver], localOnly: Boolean, settings: IvySettings, updateOptions: UpdateOptions, log: Logger): DependencyResolver =
|
||||
{
|
||||
val newDefault = new ChainResolver {
|
||||
// Technically, this should be applied to module configurations.
|
||||
// That would require custom subclasses of all resolver types in ConvertResolver (a delegation approach does not work).
|
||||
// It would be better to get proper support into Ivy.
|
||||
// A workaround is to configure the ModuleConfiguration resolver to be a ChainResolver.
|
||||
//
|
||||
// This method is only used by the pom parsing code in Ivy to find artifacts it doesn't know about.
|
||||
// In particular, a) it looks up source and javadoc classifiers b) it looks up a main artifact for packaging="pom"
|
||||
// sbt now provides the update-classifiers or requires explicitly specifying classifiers explicitly
|
||||
// Providing a main artifact for packaging="pom" does not seem to be correct and the lookup can be expensive.
|
||||
//
|
||||
// Ideally this could just skip the lookup, but unfortunately several artifacts in practice do not follow the
|
||||
// correct behavior for packaging="pom" and so it is only skipped for source/javadoc classifiers.
|
||||
override def locate(artifact: IArtifact) = if (hasImplicitClassifier(artifact)) null else super.locate(artifact)
|
||||
def resolverChain(name: String, resolvers: Seq[Resolver], localOnly: Boolean, settings: IvySettings, updateOptions: UpdateOptions, log: Logger): DependencyResolver = {
|
||||
def mapResolvers(rs: Seq[Resolver]) = rs.map(r => ConvertResolver(r, settings, log))
|
||||
val (projectResolvers, rest) = resolvers.partition(_.name == "inter-project")
|
||||
if (projectResolvers.isEmpty) new ivyint.SbtChainResolver(name, mapResolvers(rest), settings, updateOptions, log)
|
||||
else {
|
||||
// Here we set up a "first repo wins" chain resolver
|
||||
val delegate = new ivyint.SbtChainResolver(name + "-delegate", mapResolvers(rest), settings, updateOptions, log)
|
||||
val prs = mapResolvers(projectResolvers)
|
||||
// Here we construct a chain resolver which will FORCE looking at the project resolver first.
|
||||
new ivyint.SbtChainResolver(name,
|
||||
prs :+ delegate,
|
||||
settings,
|
||||
UpdateOptions().withLatestSnapshots(false),
|
||||
log)
|
||||
|
||||
override def getDependency(dd: DependencyDescriptor, data: ResolveData) =
|
||||
{
|
||||
if (data.getOptions.getLog != LogOptions.LOG_QUIET)
|
||||
Message.info("Resolving " + dd.getDependencyRevisionId + " ...")
|
||||
val gd = doGetDependency(dd, data)
|
||||
val mod = resetArtifactResolver(gd)
|
||||
mod
|
||||
}
|
||||
// Modified implementation of ChainResolver#getDependency.
|
||||
// When the dependency is changing, it will check all resolvers on the chain
|
||||
// regardless of what the "latest strategy" is set, and look for the published date
|
||||
// or the module descriptor to sort them.
|
||||
// This implementation also skips resolution if "return first" is set to true,
|
||||
// and if a previously resolved or cached revision has been found.
|
||||
def doGetDependency(dd: DependencyDescriptor, data0: ResolveData): ResolvedModuleRevision =
|
||||
{
|
||||
val useLatest = (dd.isChanging || (isChanging(dd.getDependencyRevisionId))) && updateOptions.latestSnapshots
|
||||
if (useLatest) {
|
||||
Message.verbose(s"${getName} is changing. Checking all resolvers on the chain")
|
||||
}
|
||||
val data = new ResolveData(data0, doValidate(data0))
|
||||
val resolved = Option(data.getCurrentResolvedModuleRevision)
|
||||
val resolvedOrCached =
|
||||
resolved orElse {
|
||||
Message.verbose(getName + ": Checking cache for: " + dd)
|
||||
Option(findModuleInCache(dd, data, true)) map { mr =>
|
||||
Message.verbose(getName + ": module revision found in cache: " + mr.getId)
|
||||
forcedRevision(mr)
|
||||
}
|
||||
}
|
||||
var temp: Option[ResolvedModuleRevision] =
|
||||
if (useLatest) None
|
||||
else resolvedOrCached
|
||||
val resolvers = getResolvers.toArray.toVector collect { case x: DependencyResolver => x }
|
||||
val results = resolvers map { x =>
|
||||
// if the revision is cached and isReturnFirst is set, don't bother hitting any resolvers
|
||||
if (isReturnFirst && temp.isDefined && !useLatest) Right(None)
|
||||
else {
|
||||
val resolver = x
|
||||
val oldLatest: Option[LatestStrategy] = setLatestIfRequired(resolver, Option(getLatestStrategy))
|
||||
try {
|
||||
val previouslyResolved = temp
|
||||
// if the module qualifies as changing, then resolve all resolvers
|
||||
if (useLatest) data.setCurrentResolvedModuleRevision(None.orNull)
|
||||
else data.setCurrentResolvedModuleRevision(temp.orNull)
|
||||
temp = Option(resolver.getDependency(dd, data))
|
||||
val retval = Right(
|
||||
if (temp eq previouslyResolved) None
|
||||
else if (useLatest) temp map { x =>
|
||||
(reparseModuleDescriptor(dd, data, resolver, x), resolver)
|
||||
}
|
||||
else temp map { x => (forcedRevision(x), resolver) }
|
||||
)
|
||||
retval
|
||||
} catch {
|
||||
case ex: Exception =>
|
||||
Message.verbose("problem occurred while resolving " + dd + " with " + resolver
|
||||
+ ": " + IvyStringUtils.getStackTrace(ex))
|
||||
Left(ex)
|
||||
} finally {
|
||||
oldLatest map { _ => doSetLatestStrategy(resolver, oldLatest) }
|
||||
checkInterrupted
|
||||
}
|
||||
}
|
||||
}
|
||||
val errors = results collect { case Left(e) => e }
|
||||
val foundRevisions: Vector[(ResolvedModuleRevision, DependencyResolver)] = results collect { case Right(Some(x)) => x }
|
||||
val sorted =
|
||||
if (useLatest) (foundRevisions.sortBy {
|
||||
case (rmr, _) =>
|
||||
rmr.getDescriptor.getPublicationDate.getTime
|
||||
}).reverse.headOption map {
|
||||
case (rmr, resolver) =>
|
||||
// Now that we know the real latest revision, let's force Ivy to use it
|
||||
val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver)
|
||||
artifactOpt match {
|
||||
case None if resolver.getName == "inter-project" => // do nothing
|
||||
case None => throw new RuntimeException("\t" + resolver.getName
|
||||
+ ": no ivy file nor artifact found for " + rmr)
|
||||
case Some(artifactRef) =>
|
||||
val systemMd = toSystem(rmr.getDescriptor)
|
||||
getRepositoryCacheManager.cacheModuleDescriptor(resolver, artifactRef,
|
||||
toSystem(dd), systemMd.getAllArtifacts().head, None.orNull, getCacheOptions(data))
|
||||
}
|
||||
rmr
|
||||
}
|
||||
else foundRevisions.reverse.headOption map { _._1 }
|
||||
val mrOpt: Option[ResolvedModuleRevision] = sorted orElse resolvedOrCached
|
||||
mrOpt match {
|
||||
case None if errors.size == 1 =>
|
||||
errors.head match {
|
||||
case e: RuntimeException => throw e
|
||||
case e: ParseException => throw e
|
||||
case e: Throwable => throw new RuntimeException(e.toString, e)
|
||||
}
|
||||
case None if errors.size > 1 =>
|
||||
val err = (errors.toList map { IvyStringUtils.getErrorMessage }).mkString("\n\t", "\n\t", "\n")
|
||||
throw new RuntimeException(s"several problems occurred while resolving $dd:$err")
|
||||
case _ =>
|
||||
if (resolved == mrOpt) resolved.orNull
|
||||
else (mrOpt map { resolvedRevision }).orNull
|
||||
}
|
||||
}
|
||||
// Ivy seem to not want to use the module descriptor found at the latest resolver
|
||||
private[this] def reparseModuleDescriptor(dd: DependencyDescriptor, data: ResolveData, resolver: DependencyResolver, rmr: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
Option(resolver.findIvyFileRef(dd, data)) flatMap { ivyFile =>
|
||||
ivyFile.getResource match {
|
||||
case r: FileResource =>
|
||||
try {
|
||||
val parser = rmr.getDescriptor.getParser
|
||||
val md = parser.parseDescriptor(settings, r.getFile.toURL, r, false)
|
||||
Some(new ResolvedModuleRevision(resolver, resolver, md, rmr.getReport, true))
|
||||
} catch {
|
||||
case _: ParseException => None
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
} getOrElse rmr
|
||||
/** Ported from BasicResolver#findFirstAirfactRef. */
|
||||
private[this] def findFirstArtifactRef(md: ModuleDescriptor, dd: DependencyDescriptor, data: ResolveData, resolver: DependencyResolver): Option[ResolvedResource] =
|
||||
{
|
||||
def artifactRef(artifact: IArtifact, date: Date): Option[ResolvedResource] =
|
||||
resolver match {
|
||||
case resolver: BasicResolver =>
|
||||
IvyContext.getContext.set(resolver.getName + ".artifact", artifact)
|
||||
try {
|
||||
Option(resolver.doFindArtifactRef(artifact, date)) orElse {
|
||||
Option(artifact.getUrl) map { url =>
|
||||
Message.verbose("\tusing url for " + artifact + ": " + url)
|
||||
val resource =
|
||||
if ("file" == url.getProtocol) new FileResource(new IFileRepository(), new File(url.getPath()))
|
||||
else new URLResource(url)
|
||||
new ResolvedResource(resource, artifact.getModuleRevisionId.getRevision)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
IvyContext.getContext.set(resolver.getName + ".artifact", null)
|
||||
}
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
val artifactRefs = md.getConfigurations.toIterator flatMap { conf =>
|
||||
md.getArtifacts(conf.getName).toIterator flatMap { af =>
|
||||
artifactRef(af, data.getDate).toIterator
|
||||
}
|
||||
}
|
||||
if (artifactRefs.hasNext) Some(artifactRefs.next)
|
||||
else None
|
||||
}
|
||||
/** Ported from ChainResolver#forcedRevision. */
|
||||
private[this] def forcedRevision(rmr: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
new ResolvedModuleRevision(rmr.getResolver, rmr.getArtifactResolver, rmr.getDescriptor, rmr.getReport, true)
|
||||
/** Ported from ChainResolver#resolvedRevision. */
|
||||
private[this] def resolvedRevision(rmr: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
if (isDual) new ResolvedModuleRevision(rmr.getResolver, this, rmr.getDescriptor, rmr.getReport, rmr.isForce)
|
||||
else rmr
|
||||
/** Ported from ChainResolver#setLatestIfRequired. */
|
||||
private[this] def setLatestIfRequired(resolver: DependencyResolver, latest: Option[LatestStrategy]): Option[LatestStrategy] =
|
||||
latestStrategyName(resolver) match {
|
||||
case Some(latestName) if latestName != "default" =>
|
||||
val oldLatest = latestStrategy(resolver)
|
||||
doSetLatestStrategy(resolver, latest)
|
||||
oldLatest
|
||||
case _ => None
|
||||
}
|
||||
/** Ported from ChainResolver#getLatestStrategyName. */
|
||||
private[this] def latestStrategyName(resolver: DependencyResolver): Option[String] =
|
||||
resolver match {
|
||||
case r: HasLatestStrategy => Some(r.getLatest)
|
||||
case _ => None
|
||||
}
|
||||
/** Ported from ChainResolver#getLatest. */
|
||||
private[this] def latestStrategy(resolver: DependencyResolver): Option[LatestStrategy] =
|
||||
resolver match {
|
||||
case r: HasLatestStrategy => Some(r.getLatestStrategy)
|
||||
case _ => None
|
||||
}
|
||||
/** Ported from ChainResolver#setLatest. */
|
||||
private[this] def doSetLatestStrategy(resolver: DependencyResolver, latest: Option[LatestStrategy]): Option[LatestStrategy] =
|
||||
resolver match {
|
||||
case r: HasLatestStrategy =>
|
||||
val oldLatest = latestStrategy(resolver)
|
||||
r.setLatestStrategy(latest.orNull)
|
||||
oldLatest
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
newDefault.setName(name)
|
||||
newDefault.setReturnFirst(true)
|
||||
newDefault.setCheckmodified(false)
|
||||
for (sbtResolver <- resolvers) {
|
||||
log.debug("\t" + sbtResolver)
|
||||
newDefault.add(ConvertResolver(sbtResolver, settings, log))
|
||||
}
|
||||
newDefault
|
||||
}
|
||||
}
|
||||
def addResolvers(resolvers: Seq[Resolver], settings: IvySettings, log: Logger) {
|
||||
for (r <- resolvers) {
|
||||
log.debug("\t" + r)
|
||||
|
|
@ -528,7 +332,7 @@ private object IvySbt {
|
|||
// if there are problems with this, a less aggressive fix might be to only reset the artifact resolver when it is a ProjectResolver
|
||||
// a possible problem is that fetching artifacts is slower, due to the full chain being the artifact resolver instead of the specific resolver
|
||||
// This also fixes #760, which occurs when metadata exists in a repository, but the artifact doesn't.
|
||||
private[this] def resetArtifactResolver(resolved: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
private[sbt] def resetArtifactResolver(resolved: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
if (resolved eq null)
|
||||
null
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ object Resolver {
|
|||
private[sbt] def useSecureResolvers = sys.props.get("sbt.repository.secure") map { _.toLowerCase == "true" } getOrElse true
|
||||
|
||||
val TypesafeRepositoryRoot = typesafeRepositoryRoot(useSecureResolvers)
|
||||
val SbtPluginRepositoryRoot = "http://repo.scala-sbt.org/scalasbt"
|
||||
val SbtPluginRepositoryRoot = sbtPluginRepositoryRoot(useSecureResolvers)
|
||||
val SonatypeRepositoryRoot = "https://oss.sonatype.org/content/repositories"
|
||||
val JavaNet2RepositoryName = "java.net Maven2 Repository"
|
||||
val JavaNet2RepositoryRoot = javanet2RepositoryRoot(useSecureResolvers)
|
||||
|
|
@ -164,6 +164,8 @@ object Resolver {
|
|||
else "http://download.java.net/maven/2"
|
||||
// TODO: This switch is only kept for backward compatibility. Hardcode to HTTPS in the future.
|
||||
private[sbt] def typesafeRepositoryRoot(secure: Boolean) = (if (secure) "https" else "http") + "://repo.typesafe.com/typesafe"
|
||||
// TODO: This switch is only kept for backward compatibility. Hardcode to HTTPS in the future.
|
||||
private[sbt] def sbtPluginRepositoryRoot(secure: Boolean) = (if (secure) "https" else "http") + "://repo.scala-sbt.org/scalasbt"
|
||||
|
||||
// obsolete: kept only for launcher compatibility
|
||||
private[sbt] val ScalaToolsReleasesName = "Sonatype OSS Releases"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,230 @@
|
|||
package sbt
|
||||
package ivyint
|
||||
|
||||
import java.io.File
|
||||
import java.text.ParseException
|
||||
import java.util.Date
|
||||
|
||||
import org.apache.ivy.core.settings.IvySettings
|
||||
import org.apache.ivy.core.{ IvyContext, LogOptions }
|
||||
import org.apache.ivy.core.module.descriptor.{ ModuleDescriptor, DependencyDescriptor, Artifact => IArtifact }
|
||||
import org.apache.ivy.core.resolve.{ ResolvedModuleRevision, ResolveData }
|
||||
import org.apache.ivy.plugins.latest.LatestStrategy
|
||||
import org.apache.ivy.plugins.repository.file.{ FileRepository => IFileRepository, FileResource }
|
||||
import org.apache.ivy.plugins.repository.url.URLResource
|
||||
import org.apache.ivy.plugins.resolver.{ ChainResolver, BasicResolver, DependencyResolver }
|
||||
import org.apache.ivy.plugins.resolver.util.{ HasLatestStrategy, ResolvedResource }
|
||||
import org.apache.ivy.util.{ Message, MessageLogger, StringUtils => IvyStringUtils }
|
||||
|
||||
class SbtChainResolver(name: String, resolvers: Seq[DependencyResolver], settings: IvySettings, updateOptions: UpdateOptions, log: Logger) extends ChainResolver {
|
||||
// TODO - We need to special case the project resolver so it always "wins" when resolving with inter-project dependencies.
|
||||
|
||||
// Initialize ourselves.
|
||||
setName(name)
|
||||
setReturnFirst(true)
|
||||
setCheckmodified(false)
|
||||
// Here we append all the resolvers we were passed *AND* look for
|
||||
// a project resolver, which we will special-case.
|
||||
resolvers.foreach(add)
|
||||
|
||||
// Technically, this should be applied to module configurations.
|
||||
// That would require custom subclasses of all resolver types in ConvertResolver (a delegation approach does not work).
|
||||
// It would be better to get proper support into Ivy.
|
||||
// A workaround is to configure the ModuleConfiguration resolver to be a ChainResolver.
|
||||
//
|
||||
// This method is only used by the pom parsing code in Ivy to find artifacts it doesn't know about.
|
||||
// In particular, a) it looks up source and javadoc classifiers b) it looks up a main artifact for packaging="pom"
|
||||
// sbt now provides the update-classifiers or requires explicitly specifying classifiers explicitly
|
||||
// Providing a main artifact for packaging="pom" does not seem to be correct and the lookup can be expensive.
|
||||
//
|
||||
// Ideally this could just skip the lookup, but unfortunately several artifacts in practice do not follow the
|
||||
// correct behavior for packaging="pom" and so it is only skipped for source/javadoc classifiers.
|
||||
override def locate(artifact: IArtifact) = if (IvySbt.hasImplicitClassifier(artifact)) null else super.locate(artifact)
|
||||
|
||||
override def getDependency(dd: DependencyDescriptor, data: ResolveData) =
|
||||
{
|
||||
if (data.getOptions.getLog != LogOptions.LOG_QUIET)
|
||||
Message.info("Resolving " + dd.getDependencyRevisionId + " ...")
|
||||
val gd = doGetDependency(dd, data)
|
||||
val mod = IvySbt.resetArtifactResolver(gd)
|
||||
mod
|
||||
}
|
||||
// Modified implementation of ChainResolver#getDependency.
|
||||
// When the dependency is changing, it will check all resolvers on the chain
|
||||
// regardless of what the "latest strategy" is set, and look for the published date
|
||||
// or the module descriptor to sort them.
|
||||
// This implementation also skips resolution if "return first" is set to true,
|
||||
// and if a previously resolved or cached revision has been found.
|
||||
def doGetDependency(dd: DependencyDescriptor, data0: ResolveData): ResolvedModuleRevision =
|
||||
{
|
||||
val useLatest = (dd.isChanging || (IvySbt.isChanging(dd.getDependencyRevisionId))) && updateOptions.latestSnapshots
|
||||
if (useLatest) {
|
||||
Message.verbose(s"${getName} is changing. Checking all resolvers on the chain")
|
||||
}
|
||||
val data = new ResolveData(data0, doValidate(data0))
|
||||
val resolved = Option(data.getCurrentResolvedModuleRevision)
|
||||
val resolvedOrCached =
|
||||
resolved orElse {
|
||||
Message.verbose(getName + ": Checking cache for: " + dd)
|
||||
Option(findModuleInCache(dd, data, true)) map { mr =>
|
||||
Message.verbose(getName + ": module revision found in cache: " + mr.getId)
|
||||
forcedRevision(mr)
|
||||
}
|
||||
}
|
||||
var temp: Option[ResolvedModuleRevision] =
|
||||
if (useLatest) None
|
||||
else resolvedOrCached
|
||||
val resolvers = getResolvers.toArray.toVector collect { case x: DependencyResolver => x }
|
||||
val results = resolvers map { x =>
|
||||
// if the revision is cached and isReturnFirst is set, don't bother hitting any resolvers
|
||||
if (isReturnFirst && temp.isDefined && !useLatest) Right(None)
|
||||
else {
|
||||
val resolver = x
|
||||
val oldLatest: Option[LatestStrategy] = setLatestIfRequired(resolver, Option(getLatestStrategy))
|
||||
try {
|
||||
val previouslyResolved = temp
|
||||
// if the module qualifies as changing, then resolve all resolvers
|
||||
if (useLatest) data.setCurrentResolvedModuleRevision(None.orNull)
|
||||
else data.setCurrentResolvedModuleRevision(temp.orNull)
|
||||
temp = Option(resolver.getDependency(dd, data))
|
||||
val retval = Right(
|
||||
if (temp eq previouslyResolved) None
|
||||
else if (useLatest) temp map { x =>
|
||||
(reparseModuleDescriptor(dd, data, resolver, x), resolver)
|
||||
}
|
||||
else temp map { x => (forcedRevision(x), resolver) }
|
||||
)
|
||||
retval
|
||||
} catch {
|
||||
case ex: Exception =>
|
||||
Message.verbose("problem occurred while resolving " + dd + " with " + resolver
|
||||
+ ": " + IvyStringUtils.getStackTrace(ex))
|
||||
Left(ex)
|
||||
} finally {
|
||||
oldLatest map { _ => doSetLatestStrategy(resolver, oldLatest) }
|
||||
checkInterrupted
|
||||
}
|
||||
}
|
||||
}
|
||||
val errors = results collect { case Left(e) => e }
|
||||
val foundRevisions: Vector[(ResolvedModuleRevision, DependencyResolver)] = results collect { case Right(Some(x)) => x }
|
||||
val sorted =
|
||||
if (useLatest) (foundRevisions.sortBy {
|
||||
case (rmr, _) =>
|
||||
rmr.getDescriptor.getPublicationDate.getTime
|
||||
}).reverse.headOption map {
|
||||
case (rmr, resolver) =>
|
||||
// Now that we know the real latest revision, let's force Ivy to use it
|
||||
val artifactOpt = findFirstArtifactRef(rmr.getDescriptor, dd, data, resolver)
|
||||
artifactOpt match {
|
||||
case None if resolver.getName == "inter-project" => // do nothing
|
||||
case None => throw new RuntimeException("\t" + resolver.getName
|
||||
+ ": no ivy file nor artifact found for " + rmr)
|
||||
case Some(artifactRef) =>
|
||||
val systemMd = toSystem(rmr.getDescriptor)
|
||||
getRepositoryCacheManager.cacheModuleDescriptor(resolver, artifactRef,
|
||||
toSystem(dd), systemMd.getAllArtifacts().head, None.orNull, getCacheOptions(data))
|
||||
}
|
||||
rmr
|
||||
}
|
||||
else foundRevisions.reverse.headOption map { _._1 }
|
||||
val mrOpt: Option[ResolvedModuleRevision] = sorted orElse resolvedOrCached
|
||||
mrOpt match {
|
||||
case None if errors.size == 1 =>
|
||||
errors.head match {
|
||||
case e: RuntimeException => throw e
|
||||
case e: ParseException => throw e
|
||||
case e: Throwable => throw new RuntimeException(e.toString, e)
|
||||
}
|
||||
case None if errors.size > 1 =>
|
||||
val err = (errors.toList map { IvyStringUtils.getErrorMessage }).mkString("\n\t", "\n\t", "\n")
|
||||
throw new RuntimeException(s"several problems occurred while resolving $dd:$err")
|
||||
case _ =>
|
||||
if (resolved == mrOpt) resolved.orNull
|
||||
else (mrOpt map { resolvedRevision }).orNull
|
||||
}
|
||||
}
|
||||
// Ivy seem to not want to use the module descriptor found at the latest resolver
|
||||
private[this] def reparseModuleDescriptor(dd: DependencyDescriptor, data: ResolveData, resolver: DependencyResolver, rmr: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
Option(resolver.findIvyFileRef(dd, data)) flatMap { ivyFile =>
|
||||
ivyFile.getResource match {
|
||||
case r: FileResource =>
|
||||
try {
|
||||
val parser = rmr.getDescriptor.getParser
|
||||
val md = parser.parseDescriptor(settings, r.getFile.toURL, r, false)
|
||||
Some(new ResolvedModuleRevision(resolver, resolver, md, rmr.getReport, true))
|
||||
} catch {
|
||||
case _: ParseException => None
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
} getOrElse rmr
|
||||
/** Ported from BasicResolver#findFirstAirfactRef. */
|
||||
private[this] def findFirstArtifactRef(md: ModuleDescriptor, dd: DependencyDescriptor, data: ResolveData, resolver: DependencyResolver): Option[ResolvedResource] =
|
||||
{
|
||||
def artifactRef(artifact: IArtifact, date: Date): Option[ResolvedResource] =
|
||||
resolver match {
|
||||
case resolver: BasicResolver =>
|
||||
IvyContext.getContext.set(resolver.getName + ".artifact", artifact)
|
||||
try {
|
||||
Option(resolver.doFindArtifactRef(artifact, date)) orElse {
|
||||
Option(artifact.getUrl) map { url =>
|
||||
Message.verbose("\tusing url for " + artifact + ": " + url)
|
||||
val resource =
|
||||
if ("file" == url.getProtocol) new FileResource(new IFileRepository(), new File(url.getPath()))
|
||||
else new URLResource(url)
|
||||
new ResolvedResource(resource, artifact.getModuleRevisionId.getRevision)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
IvyContext.getContext.set(resolver.getName + ".artifact", null)
|
||||
}
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
val artifactRefs = md.getConfigurations.toIterator flatMap { conf =>
|
||||
md.getArtifacts(conf.getName).toIterator flatMap { af =>
|
||||
artifactRef(af, data.getDate).toIterator
|
||||
}
|
||||
}
|
||||
if (artifactRefs.hasNext) Some(artifactRefs.next)
|
||||
else None
|
||||
}
|
||||
/** Ported from ChainResolver#forcedRevision. */
|
||||
private[this] def forcedRevision(rmr: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
new ResolvedModuleRevision(rmr.getResolver, rmr.getArtifactResolver, rmr.getDescriptor, rmr.getReport, true)
|
||||
/** Ported from ChainResolver#resolvedRevision. */
|
||||
private[this] def resolvedRevision(rmr: ResolvedModuleRevision): ResolvedModuleRevision =
|
||||
if (isDual) new ResolvedModuleRevision(rmr.getResolver, this, rmr.getDescriptor, rmr.getReport, rmr.isForce)
|
||||
else rmr
|
||||
/** Ported from ChainResolver#setLatestIfRequired. */
|
||||
private[this] def setLatestIfRequired(resolver: DependencyResolver, latest: Option[LatestStrategy]): Option[LatestStrategy] =
|
||||
latestStrategyName(resolver) match {
|
||||
case Some(latestName) if latestName != "default" =>
|
||||
val oldLatest = latestStrategy(resolver)
|
||||
doSetLatestStrategy(resolver, latest)
|
||||
oldLatest
|
||||
case _ => None
|
||||
}
|
||||
/** Ported from ChainResolver#getLatestStrategyName. */
|
||||
private[this] def latestStrategyName(resolver: DependencyResolver): Option[String] =
|
||||
resolver match {
|
||||
case r: HasLatestStrategy => Some(r.getLatest)
|
||||
case _ => None
|
||||
}
|
||||
/** Ported from ChainResolver#getLatest. */
|
||||
private[this] def latestStrategy(resolver: DependencyResolver): Option[LatestStrategy] =
|
||||
resolver match {
|
||||
case r: HasLatestStrategy => Some(r.getLatestStrategy)
|
||||
case _ => None
|
||||
}
|
||||
/** Ported from ChainResolver#setLatest. */
|
||||
private[this] def doSetLatestStrategy(resolver: DependencyResolver, latest: Option[LatestStrategy]): Option[LatestStrategy] =
|
||||
resolver match {
|
||||
case r: HasLatestStrategy =>
|
||||
val oldLatest = latestStrategy(resolver)
|
||||
r.setLatestStrategy(latest.orNull)
|
||||
oldLatest
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
|
@ -1655,7 +1655,15 @@ object Classpaths {
|
|||
import xsbti.Predefined
|
||||
repo match {
|
||||
case m: xsbti.MavenRepository => MavenRepository(m.id, m.url.toString)
|
||||
case i: xsbti.IvyRepository => Resolver.url(i.id, i.url)(Patterns(i.ivyPattern :: Nil, i.artifactPattern :: Nil, mavenCompatible(i), descriptorOptional(i), skipConsistencyCheck(i)))
|
||||
case i: xsbti.IvyRepository =>
|
||||
val patterns = Patterns(i.ivyPattern :: Nil, i.artifactPattern :: Nil, mavenCompatible(i), descriptorOptional(i), skipConsistencyCheck(i))
|
||||
i.url.getProtocol match {
|
||||
case "file" =>
|
||||
// This hackery is to deal suitably with UNC paths on Windows. Once we can assume Java7, Paths should save us from this.
|
||||
val file = try { new File(i.url.toURI) } catch { case e: java.net.URISyntaxException => new File(i.url.getPath) }
|
||||
Resolver.file(i.id, file)(patterns)
|
||||
case _ => Resolver.url(i.id, i.url)(patterns)
|
||||
}
|
||||
case p: xsbti.PredefinedRepository => p.id match {
|
||||
case Predefined.Local => Resolver.defaultLocal
|
||||
case Predefined.MavenLocal => Resolver.mavenLocal
|
||||
|
|
|
|||
|
|
@ -439,7 +439,8 @@ object Load {
|
|||
|
||||
val memoSettings = new mutable.HashMap[File, LoadedSbtFile]
|
||||
def loadProjects(ps: Seq[Project], createRoot: Boolean) = {
|
||||
loadTransitive(ps, normBase, plugs, () => eval, config.injectSettings, Nil, memoSettings, config.log, createRoot, uri, config.pluginManagement.context, Nil)
|
||||
val result = loadTransitive(ps, normBase, plugs, () => eval, config.injectSettings, Nil, memoSettings, config.log, createRoot, uri, config.pluginManagement.context, Nil)
|
||||
result
|
||||
}
|
||||
|
||||
val loadedProjectsRaw = loadProjects(initialProjects, !hasRootAlreadyDefined)
|
||||
|
|
@ -567,14 +568,14 @@ object Load {
|
|||
case Seq(next, rest @ _*) =>
|
||||
log.debug(s"[Loading] Loading project ${next.id} @ ${next.base}")
|
||||
val (finished, discovered, generated) = discoverAndLoad(next)
|
||||
loadTransitive(rest ++ discovered, buildBase, plugins, eval, injectSettings, acc :+ finished, memoSettings, log, false, buildUri, context, generated)
|
||||
loadTransitive(rest ++ discovered, buildBase, plugins, eval, injectSettings, acc :+ finished, memoSettings, log, false, buildUri, context, generated ++ generatedConfigClassFiles)
|
||||
case Nil if makeOrDiscoverRoot =>
|
||||
log.debug(s"[Loading] Scanning directory ${buildBase}")
|
||||
discover(AddSettings.defaultSbtFiles, buildBase) match {
|
||||
case DiscoveredProjects(Some(root), discovered, files, generated) =>
|
||||
log.debug(s"[Loading] Found root project ${root.id} w/ remaining ${discovered.map(_.id).mkString(",")}")
|
||||
val finalRoot = finalizeProject(root, files)
|
||||
loadTransitive(discovered, buildBase, plugins, eval, injectSettings, finalRoot +: acc, memoSettings, log, false, buildUri, context, generated)
|
||||
loadTransitive(discovered, buildBase, plugins, eval, injectSettings, finalRoot +: acc, memoSettings, log, false, buildUri, context, generated ++ generatedConfigClassFiles)
|
||||
// Here we need to create a root project...
|
||||
case DiscoveredProjects(None, discovered, files, generated) =>
|
||||
log.debug(s"[Loading] Found non-root projects ${discovered.map(_.id).mkString(",")}")
|
||||
|
|
@ -587,7 +588,7 @@ object Load {
|
|||
val root = finalizeProject(Build.defaultAggregatedProject(defaultID, buildBase, refs), files)
|
||||
val result = root +: (acc ++ otherProjects.projects)
|
||||
log.debug(s"[Loading] Done in ${buildBase}, returning: ${result.map(_.id).mkString("(", ", ", ")")}")
|
||||
LoadedProjects(result, generated ++ otherGenerated)
|
||||
LoadedProjects(result, generated ++ otherGenerated ++ generatedConfigClassFiles)
|
||||
}
|
||||
case Nil =>
|
||||
log.debug(s"[Loading] Done in ${buildBase}, returning: ${acc.map(_.id).mkString("(", ", ", ")")}")
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package sbt
|
|||
|
||||
import internals.{
|
||||
DslEntry,
|
||||
DslSetting,
|
||||
DslConfigs,
|
||||
DslEnablePlugins,
|
||||
DslDisablePlugins
|
||||
}
|
||||
|
|
@ -10,4 +10,6 @@ import internals.{
|
|||
package object dsl {
|
||||
def enablePlugins(ps: AutoPlugin*): DslEntry = DslEnablePlugins(ps)
|
||||
def disablePlugins(ps: AutoPlugin*): DslEntry = DslDisablePlugins(ps)
|
||||
def configs(cs: Configuration*): DslEntry = DslConfigs(cs)
|
||||
|
||||
}
|
||||
|
|
@ -54,4 +54,8 @@ case class DslEnablePlugins(plugins: Seq[AutoPlugin]) extends ProjectManipulatio
|
|||
case class DslDisablePlugins(plugins: Seq[AutoPlugin]) extends ProjectManipulation {
|
||||
override val toFunction: Project => Project = _.disablePlugins(plugins: _*)
|
||||
}
|
||||
/** Represents registering a set of configurations with the current project. */
|
||||
case class DslConfigs(cs: Seq[Configuration]) extends ProjectManipulation {
|
||||
override val toFunction: Project => Project = _.configs(cs: _*)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@
|
|||
|
||||
### Fixes with compatibility implications
|
||||
|
||||
- Maven Central Repository, Java.net Maven 2 Repository, and Typesafe Repository now defaults to HTTPS. (See below)
|
||||
- Maven Central Repository, Java.net Maven 2 Repository, Typesafe Repository, and sbt Plugin repository now defaults to HTTPS. (See below)
|
||||
- `ThisProject` used to resolve to the root project in a build even when it's place in `subproj/build.sbt`. sbt 0.13.6 fixes it to resolve to the sub project. [#1194][1194]/[#1358][1358] by [@dansanduleac][@dansanduleac]
|
||||
- Global plugins classpath used to be injected into every build. This will no longer be the case. [#1347][1347]/[#1352][1352] by [@dansanduleac][@dansanduleac]
|
||||
- Fixes `newer` command in scripted. [#1419][1419] by [@jroper][@jroper]
|
||||
|
|
@ -130,7 +130,7 @@ Thanks to Sonatype, HTTPS access to Maven Central Repository is available to pub
|
|||
|
||||
-Dsbt.repository.secure=false
|
||||
|
||||
Java.net Maven 2 repository and Typesafe repository also defaults to HTTPS.
|
||||
Java.net Maven 2 repository, Typesafe repository, and sbt Plugin repository also defaults to HTTPS.
|
||||
|
||||
[#1494][1494] by [@rtyley][@rtyley], [#1536][1536] by [@benmccann][@benmccann], and [#1541][1541] by [@eed3si9n][@eed3si9n].
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
lazy val root = project in file(".")
|
||||
|
||||
lazy val js = project
|
||||
|
||||
def bigDataSesameVersion = "2.6.10"
|
||||
|
||||
libraryDependencies += "foo" % "bar" % bigDataSesameVersion
|
||||
|
|
@ -0,0 +1 @@
|
|||
bintraySettings
|
||||
|
|
@ -0,0 +1 @@
|
|||
addSbtPlugin("me.lessis" % "bintray-sbt" % "0.1.2")
|
||||
|
|
@ -0,0 +1 @@
|
|||
> name
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
lazy val OtherScala = config("other-scala").hide
|
||||
|
||||
configs(OtherScala)
|
||||
|
||||
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.11.1" % OtherScala.name
|
||||
|
||||
managedClasspath in OtherScala := Classpaths.managedJars(OtherScala, classpathTypes.value, update.value)
|
||||
|
||||
// Hack in the scala instance
|
||||
scalaInstance := {
|
||||
val rawJars = (managedClasspath in OtherScala).value.map(_.data)
|
||||
val scalaHome = (target.value / "scala-home")
|
||||
def removeVersion(name: String): String =
|
||||
name.replaceAll("\\-2.11.1", "")
|
||||
for(jar <- rawJars) {
|
||||
val tjar = scalaHome / s"lib/${removeVersion(jar.getName)}"
|
||||
IO.copyFile(jar, tjar)
|
||||
}
|
||||
IO.listFiles(scalaHome).foreach(f => System.err.println(s" * $f}"))
|
||||
ScalaInstance(scalaHome, appConfiguration.value.provider.scalaProvider.launcher)
|
||||
}
|
||||
|
||||
|
||||
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test"
|
||||
|
||||
libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.3.3" % "test"
|
||||
|
||||
scalaVersion := "2.11.0"
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package akka.actor
|
||||
|
||||
import org.junit._
|
||||
|
||||
class BadTest {
|
||||
|
||||
@Test
|
||||
def testCpIssue(): Unit = {
|
||||
// TODO - This is merely the laziest way to run the test. What we want to do:
|
||||
// * Load something from our own classloader that's INSIDE the scala library
|
||||
// * Try to load that same something from the THREAD CONTEXT classloader.
|
||||
// * Ensure we can do both, i.e. the second used to be filtered and broken.
|
||||
val current = Thread.currentThread.getContextClassLoader
|
||||
val mine = this.getClass.getClassLoader
|
||||
val system = ActorSystem()
|
||||
def evilGetThreadExectionContextName =
|
||||
system.asInstanceOf[ActorSystemImpl].internalCallingThreadExecutionContext.getClass.getName
|
||||
val expected = "scala.concurrent.Future$InternalCallbackExecutor$"
|
||||
Assert.assertEquals("Failed to grab appropriate Akka name", expected, evilGetThreadExectionContextName)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
> test
|
||||
|
|
@ -191,7 +191,12 @@ object TestFramework {
|
|||
val notInterfaceFilter = (name: String) => !interfaceFilter(name)
|
||||
val dual = new DualLoader(scalaInstance.loader, notInterfaceFilter, x => true, getClass.getClassLoader, interfaceFilter, x => false)
|
||||
val main = ClasspathUtilities.makeLoader(classpath, dual, scalaInstance, tempDir)
|
||||
ClasspathUtilities.filterByClasspath(interfaceJar +: classpath, main)
|
||||
// TODO - There's actually an issue with the classpath facility such that unmanagedScalaInstances are not added
|
||||
// to the classpath correctly. We have a temporary workaround here.
|
||||
val cp: Seq[File] =
|
||||
if (scalaInstance.isManagedVersion) interfaceJar +: classpath
|
||||
else scalaInstance.allJars ++ (interfaceJar +: classpath)
|
||||
ClasspathUtilities.filterByClasspath(cp, main)
|
||||
}
|
||||
def createTestFunction(loader: ClassLoader, taskDef: TaskDef, runner: TestRunner, testTask: TestTask): TestFunction =
|
||||
new TestFunction(taskDef, runner, (r: TestRunner) => withContextLoader(loader) { r.run(taskDef, testTask) }) { def tags = testTask.tags }
|
||||
|
|
|
|||
|
|
@ -19,6 +19,12 @@ final class ScalaInstance(val version: String, val loader: ClassLoader, val libr
|
|||
@deprecated("Only `allJars` and `jars` can be reliably provided for modularized Scala.", "0.13.0") val compilerJar: File,
|
||||
@deprecated("Only `allJars` and `jars` can be reliably provided for modularized Scala.", "0.13.0") val extraJars: Seq[File],
|
||||
val explicitActual: Option[String]) extends xsbti.compile.ScalaInstance {
|
||||
/**
|
||||
* This tells us if the scalaInstance is from a managed (i.e. ivy-resolved) scala *or*
|
||||
* if it's a free-floating ScalaInstance, in which case we need to do tricks to the classpaths we find
|
||||
* because it won't be on them.
|
||||
*/
|
||||
final def isManagedVersion = explicitActual.isDefined
|
||||
// These are to implement xsbti.ScalaInstance
|
||||
@deprecated("Only `allJars` and `jars` can be reliably provided for modularized Scala.", "0.13.0")
|
||||
def otherJars: Array[File] = extraJars.toArray
|
||||
|
|
|
|||
|
|
@ -46,6 +46,13 @@ final class SelfFirstLoader(classpath: Seq[URL], parent: ClassLoader) extends Lo
|
|||
|
||||
/** Doesn't load any classes itself, but instead verifies that all classes loaded through `parent` either come from `root` or `classpath`.*/
|
||||
final class ClasspathFilter(parent: ClassLoader, root: ClassLoader, classpath: Set[File]) extends ClassLoader(parent) {
|
||||
override def toString =
|
||||
s"""|ClasspathFilter(
|
||||
| parent = $parent
|
||||
| root = $root
|
||||
| cp = $classpath
|
||||
|)""".stripMargin
|
||||
|
||||
private[this] val directories: Seq[File] = classpath.toSeq.filter(_.isDirectory)
|
||||
override def loadClass(className: String, resolve: Boolean): Class[_] =
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,13 @@ object ClasspathUtilities {
|
|||
new URLClassLoader(Path.toURLs(paths), parent) with RawResources with NativeCopyLoader {
|
||||
override def resources = resourceMap
|
||||
override val config = new NativeCopyConfig(nativeTemp, paths, javaLibraryPaths)
|
||||
override def toString =
|
||||
s"""|URLClassLoader with NativeCopyLoader with RawResources(
|
||||
| urls = $paths,
|
||||
| parent = $parent,
|
||||
| resourceMap = ${resourceMap.keySet},
|
||||
| nativeTemp = $nativeTemp
|
||||
|)""".stripMargin
|
||||
}
|
||||
|
||||
def javaLibraryPaths: Seq[File] = IO.parseClasspath(System.getProperty("java.library.path"))
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ final class NullLoader extends ClassLoader {
|
|||
override final def loadClass(className: String, resolve: Boolean): Class[_] = throw new ClassNotFoundException("No classes can be loaded from the null loader")
|
||||
override def getResource(name: String): URL = null
|
||||
override def getResources(name: String): Enumeration[URL] = null
|
||||
override def toString = "NullLoader"
|
||||
}
|
||||
|
||||
/** Exception thrown when `loaderA` and `loaderB` load a different Class for the same name. */
|
||||
|
|
@ -84,6 +85,8 @@ class DualLoader(parentA: ClassLoader, aOnlyClasses: String => Boolean, aOnlyRes
|
|||
new DualEnumeration(urlsA, urlsB)
|
||||
}
|
||||
}
|
||||
|
||||
override def toString = s"DualLoader(a = $parentA, b = $parentB)"
|
||||
}
|
||||
|
||||
/** Concatenates `a` and `b` into a single `Enumeration`.*/
|
||||
|
|
|
|||
|
|
@ -39,9 +39,11 @@ object CrossVersionUtil
|
|||
private[${{cross.package0}}] def scalaApiVersion(v: String): Option[(Int, Int)] =
|
||||
{
|
||||
val ReleaseV = """(\d+)\.(\d+)\.(\d+)(-\d+)?""".r
|
||||
val BinCompatV = """(\d+)\.(\d+)\.(\d+)-bin(-.*)?""".r
|
||||
val NonReleaseV = """(\d+)\.(\d+)\.(\d+)(-\w+)""".r
|
||||
v match {
|
||||
case ReleaseV(x, y, z, ht) => Some((x.toInt, y.toInt))
|
||||
case BinCompatV(x, y, z, ht) => Some((x.toInt, y.toInt))
|
||||
case NonReleaseV(x, y, z, ht) if z.toInt > 0 => Some((x.toInt, y.toInt))
|
||||
case _ => None
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue