From bbb2ef3977b54dee4eb8fb20fa55f0a1a1bcfa21 Mon Sep 17 00:00:00 2001 From: OlegYch Date: Sat, 7 Apr 2018 23:27:08 +0300 Subject: [PATCH] fix retrieving deps via sftp resolver --- build.sbt | 2 +- .../librarymanagement/ConvertResolver.scala | 18 ++++++-- .../librarymanagement/SftpRepoSpec.scala | 42 +++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala diff --git a/build.sbt b/build.sbt index 0bdf600eb..4e812dccd 100644 --- a/build.sbt +++ b/build.sbt @@ -3,8 +3,8 @@ import Path._ import com.typesafe.tools.mima.core._, ProblemFilters._ val _ = { + //https://github.com/sbt/contraband/issues/122 sys.props += ("line.separator" -> "\n") - sys.props += ("file.separaror" -> "/") } def commonSettings: Seq[Setting[_]] = Seq( diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala index cc13ea745..41a571c37 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/ConvertResolver.scala @@ -7,7 +7,7 @@ import java.net.URL import java.util.Collections import org.apache.ivy.core.module.descriptor.DependencyDescriptor -import org.apache.ivy.core.resolve.ResolveData +import org.apache.ivy.core.resolve.{ DownloadOptions, ResolveData } import org.apache.ivy.core.settings.IvySettings import org.apache.ivy.plugins.repository.{ RepositoryCopyProgressListener, Resource, TransferEvent } import org.apache.ivy.plugins.resolver.{ @@ -30,6 +30,7 @@ import java.io.{ File, IOException } import org.apache.ivy.util.{ ChecksumHelper, FileUtil, Message } import org.apache.ivy.core.module.descriptor.{ Artifact => IArtifact } +import org.apache.ivy.core.report.DownloadReport import sbt.io.IO import sbt.util.Logger import sbt.librarymanagement._ @@ -181,7 +182,7 @@ private[sbt] object ConvertResolver { resolver } case repo: SshRepository => { - val resolver = new SshResolver with DescriptorRequired { + val resolver = new SshResolver with DescriptorRequired with ThreadSafeSshBasedResolver { override val managedChecksumsEnabled: Boolean = managedChecksums override def getResource(resource: Resource, dest: File): Long = get(resource, dest) } @@ -190,7 +191,7 @@ private[sbt] object ConvertResolver { resolver } case repo: SftpRepository => { - val resolver = new SFTPResolver + val resolver = new SFTPResolver with ThreadSafeSshBasedResolver initializeSSHResolver(resolver, repo, settings) resolver } @@ -406,4 +407,15 @@ private[sbt] object ConvertResolver { } } } + + private sealed trait ThreadSafeSshBasedResolver + extends org.apache.ivy.plugins.resolver.AbstractSshBasedResolver { +//uncomment to test non-threadsafe behavior +// private def lock = new Object + private val lock = org.apache.ivy.plugins.repository.ssh.SshCache.getInstance + override def download(artifacts: Array[IArtifact], options: DownloadOptions): DownloadReport = + lock.synchronized { + super.download(artifacts, options) + } + } } diff --git a/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala b/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala new file mode 100644 index 000000000..8da14644a --- /dev/null +++ b/ivy/src/test/scala/sbt/internal/librarymanagement/SftpRepoSpec.scala @@ -0,0 +1,42 @@ +package sbt.internal.librarymanagement + +import sbt.io._ +import sbt.io.syntax._ +import sbt.util.Level +import sbt.librarymanagement._ +import sbt.librarymanagement.syntax._ +import java.nio.file.Paths + +//by default this test is ignored +//to run this you need to change "repo" to point to some sftp repository which contains a dependency referring a dependency in same repo +//it will then attempt to authenticate via key file and fetch the dependency specified via "org" and "module" +class SftpRepoSpec extends BaseIvySpecification { + val repo: Option[String] = None +// val repo: Option[String] = Some("some repo") + //a dependency which depends on another in the repo + def org(repo: String) = s"com.${repo}" + def module(org: String) = org % "some-lib" % "version" + + override def resolvers = { + implicit val patterns = Resolver.defaultIvyPatterns + repo.map { repo => + val privateKeyFile = Paths.get(sys.env("HOME"), ".ssh", s"id_${repo}").toFile + Resolver.sftp(repo, s"repo.${repo}.com", 2222).as(repo, privateKeyFile) + }.toVector ++ super.resolvers + } + + "resolving multiple deps from sftp repo" should "not hang or fail" in { + repo match { + case Some(repo) => + IO.delete(currentTarget / "cache" / org(repo)) + // log.setLevel(Level.Debug) + lmEngine().retrieve(module(org(repo)), scalaModuleInfo = None, currentTarget, log) match { + case Right(v) => log.debug(v.toString()) + case Left(e) => + log.log(Level.Error, e.failedPaths.toString()) + throw e.resolveException + } + case None => log.info(s"skipped ${getClass}") + } + } +}