Merge pull request #326 from alexarchambault/topic/develop

Fixes
This commit is contained in:
Alexandre Archambault 2016-08-15 19:37:39 +02:00 committed by GitHub
commit d6cba987b9
21 changed files with 414 additions and 121 deletions

View File

@ -41,7 +41,7 @@ function isMasterOrDevelop() {
# TODO Add coverage once https://github.com/scoverage/sbt-scoverage/issues/111 is fixed # TODO Add coverage once https://github.com/scoverage/sbt-scoverage/issues/111 is fixed
SBT_COMMANDS="compile test" SBT_COMMANDS="compile test it:test"
if echo "$TRAVIS_SCALA_VERSION" | grep -q "^2\.10"; then if echo "$TRAVIS_SCALA_VERSION" | grep -q "^2\.10"; then
SBT_COMMANDS="$SBT_COMMANDS publishLocal" # to make the scripted tests happy SBT_COMMANDS="$SBT_COMMANDS publishLocal" # to make the scripted tests happy

View File

@ -20,8 +20,8 @@ build_script:
- sbt ++2.10.6 coreJVM/publishLocal cache/publishLocal # to make the scripted tests happy - sbt ++2.10.6 coreJVM/publishLocal cache/publishLocal # to make the scripted tests happy
test_script: test_script:
- ps: Start-Job { & java -jar -noverify C:\projects\coursier\coursier launch -r http://dl.bintray.com/scalaz/releases io.get-coursier:http-server-java7_2.11:1.0.0-SNAPSHOT -- -d /C:/projects/coursier/tests/jvm/src/test/resources/test-repo/http/abc.com -u user -P pass -r realm -v } - ps: Start-Job { & java -jar -noverify C:\projects\coursier\coursier launch -r http://dl.bintray.com/scalaz/releases io.get-coursier:http-server-java7_2.11:1.0.0-SNAPSHOT -- -d /C:/projects/coursier/tests/jvm/src/test/resources/test-repo/http/abc.com -u user -P pass -r realm -v }
- sbt ++2.11.8 testsJVM/test # Would node be around for testsJS/test? - sbt ++2.11.8 testsJVM/test testsJVM/it:test # Would node be around for testsJS/test?
- sbt ++2.10.6 testsJVM/test plugin/scripted - sbt ++2.10.6 testsJVM/test testsJVM/it:test plugin/scripted
cache: cache:
- C:\sbt\ - C:\sbt\
- C:\Users\appveyor\.ivy2 - C:\Users\appveyor\.ivy2

View File

@ -6,6 +6,8 @@ import MimaKeys.{ previousArtifacts, binaryIssueFilters }
val binaryCompatibilityVersion = "1.0.0-M7" val binaryCompatibilityVersion = "1.0.0-M7"
lazy val IntegrationTest = config("it") extend Test
lazy val releaseSettings = Seq( lazy val releaseSettings = Seq(
publishMavenStyle := true, publishMavenStyle := true,
licenses := Seq("Apache 2.0" -> url("http://opensource.org/licenses/Apache-2.0")), licenses := Seq("Apache 2.0" -> url("http://opensource.org/licenses/Apache-2.0")),
@ -249,11 +251,13 @@ lazy val tests = crossProject
.dependsOn(core) .dependsOn(core)
.settings(commonSettings: _*) .settings(commonSettings: _*)
.settings(noPublishSettings: _*) .settings(noPublishSettings: _*)
.configs(IntegrationTest)
.settings(Defaults.itSettings: _*)
.settings( .settings(
name := "coursier-tests", name := "coursier-tests",
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"org.scala-lang.modules" %% "scala-async" % "0.9.5" % "provided", "org.scala-lang.modules" %% "scala-async" % "0.9.5" % "provided",
"com.lihaoyi" %%% "utest" % "0.4.3" % "test" "com.lihaoyi" %%% "utest" % "0.4.3" % "test,it"
), ),
unmanagedResourceDirectories in Test += (baseDirectory in LocalRootProject).value / "tests" / "shared" / "src" / "test" / "resources", unmanagedResourceDirectories in Test += (baseDirectory in LocalRootProject).value / "tests" / "shared" / "src" / "test" / "resources",
testFrameworks += new TestFramework("utest.runner.Framework") testFrameworks += new TestFramework("utest.runner.Framework")

View File

@ -61,10 +61,10 @@ case class CommonOptions(
@Value("configuration") @Value("configuration")
@Short("c") @Short("c")
defaultConfiguration: String = "default(compile)", defaultConfiguration: String = "default(compile)",
@Help("Default artifact type (make it empty to follow POM packaging - default: jar)") @Help("Default artifact type (default: follow packaging infos, else default to jar)")
@Value("type") @Value("type")
@Short("a") @Short("a")
defaultArtifactType: String = "jar", defaultArtifactType: String = "",
@Help("Maximum number of parallel downloads (default: 6)") @Help("Maximum number of parallel downloads (default: 6)")
@Short("n") @Short("n")
parallel: Int = 6, parallel: Int = 6,

View File

@ -69,6 +69,10 @@ object MavenRepository {
} else } else
module.name module.name
val ignorePackaging = Set(
Module("org.apache.zookeeper", "zookeeper", Map.empty)
)
} }
case class MavenRepository( case class MavenRepository(
@ -76,7 +80,8 @@ case class MavenRepository(
changing: Option[Boolean] = None, changing: Option[Boolean] = None,
/** Hackish hack for sbt plugins mainly - what this does really sucks */ /** Hackish hack for sbt plugins mainly - what this does really sucks */
sbtAttrStub: Boolean = false, sbtAttrStub: Boolean = false,
authentication: Option[Authentication] = None authentication: Option[Authentication] = None,
packagingBlacklist: Set[Module] = MavenRepository.ignorePackaging
) extends Repository { ) extends Repository {
import Repository._ import Repository._
@ -260,7 +265,11 @@ case class MavenRepository(
_ <- if (xml.label == "project") \/-(()) else -\/("Project definition not found") _ <- if (xml.label == "project") \/-(()) else -\/("Project definition not found")
proj <- Pom.project(xml) proj <- Pom.project(xml)
} yield { } yield {
val packagingOpt = Pom.packagingOpt(xml) val packagingOpt =
if (packagingBlacklist(module))
None
else
Pom.packagingOpt(xml)
proj.copy( proj.copy(
configurations = defaultConfigurations, configurations = defaultConfigurations,

View File

@ -59,7 +59,7 @@ object CoursierPlugin extends AutoPlugin {
override lazy val projectSettings = Seq( override lazy val projectSettings = Seq(
coursierParallelDownloads := 6, coursierParallelDownloads := 6,
coursierMaxIterations := 50, coursierMaxIterations := 50,
coursierDefaultArtifactType := "jar", coursierDefaultArtifactType := "",
coursierChecksums := Seq(Some("SHA-1"), None), coursierChecksums := Seq(Some("SHA-1"), None),
coursierArtifactsChecksums := Seq(None), coursierArtifactsChecksums := Seq(None),
coursierCachePolicies := CachePolicy.default, coursierCachePolicies := CachePolicy.default,

View File

@ -96,16 +96,16 @@ object ResolutionError {
.toVector .toVector
.sortBy(_._1) .sortBy(_._1)
val b = new StringBuilder val b = new ArrayBuffer[String]
for ((type0, errors) <- groupedArtifactErrors) { for ((type0, errors) <- groupedArtifactErrors) {
b ++= s"${errors.size} $type0" b += s"${errors.size} $type0"
if (verbose) if (verbose)
for (err <- errors) for (err <- errors)
b ++= " " + err b += " " + err
} }
b.result() b.mkString("\n")
} }
} }
} }

View File

@ -0,0 +1,114 @@
package coursier
import java.io.File
import coursier.core.Publication
import scalaz.{ EitherT, Monad }
import scalaz.Scalaz.ToEitherOps
object SbtScalaJarsRepository {
// Will break in 2.11, where scala-parser-combinators_2.11 and scala-xml_2.11, with different
// org and versions, are thrown into the mix.
// To handle these well, we would need to fetch actual infos about the scala-* dependencies
// from actual repos, and use that from SbtScalaJarsRepository.
val looseDependencies = Map(
"scala-compiler" -> Set(
"scala-library",
"scala-reflect"
),
"scala-reflect" -> Set(
"scala-library"
)
)
}
case class SbtScalaJarsRepository(
scalaOrg: String,
scalaVersion: String,
jars: Seq[File]
) extends Repository { repo =>
val foundNames = jars.collect {
case jar if jar.getName.endsWith(".jar") =>
jar.getName.stripSuffix(".jar")
}.toSet
val dependencies = SbtScalaJarsRepository.looseDependencies
.filterKeys(foundNames)
.mapValues(_.filter(foundNames))
val artifacts = jars.collect {
case jar if jar.getName.endsWith(".jar") =>
val name = jar.getName.stripSuffix(".jar")
val mod = Module(scalaOrg, name)
val proj = Project(
mod,
scalaVersion,
dependencies.getOrElse(name, Set.empty[String]).toVector.map { depName =>
val dep = Dependency(Module(scalaOrg, depName), scalaVersion)
"compile" -> dep
},
MavenRepository.defaultConfigurations,
None,
Nil,
Nil,
Nil,
None,
None,
None,
Seq("compile" -> Publication(name, "jar", "jar", "")),
Info("", "", Nil, Nil, None)
)
(mod, scalaVersion) -> ((proj, jar))
}.toMap
val source: Artifact.Source = new Artifact.Source {
def artifacts(
dependency: Dependency,
project: Project,
overrideClassifiers: Option[Seq[String]]
) =
if (overrideClassifiers.isEmpty)
repo.artifacts.get(project.moduleVersion) match {
case Some((_, f)) =>
Seq(
Artifact(
f.toURI.toString,
Map.empty,
Map.empty,
Attributes("jar", ""),
changing = true,
None
)
)
case None =>
Nil
}
else
Nil
}
def find[F[_]](
module: Module,
version: String,
fetch: Fetch.Content[F]
)(implicit
F: Monad[F]
): EitherT[F, String, (Artifact.Source, Project)] = {
val res = artifacts.get((module, version)) match {
case None =>
s"not found in internal SBT scala JARs: $module:$version".left
case Some((p, _)) =>
(source, p).right
}
EitherT(F.point(res))
}
}

View File

@ -6,7 +6,7 @@ import java.nio.file.Files
import java.util.concurrent.{ ExecutorService, Executors } import java.util.concurrent.{ ExecutorService, Executors }
import coursier.core.{ Authentication, Publication } import coursier.core.{ Authentication, Publication }
import coursier.ivy.IvyRepository import coursier.ivy.{ IvyRepository, PropertiesPattern }
import coursier.Keys._ import coursier.Keys._
import coursier.Structure._ import coursier.Structure._
import coursier.maven.WritePom import coursier.maven.WritePom
@ -19,6 +19,7 @@ import sbt.Keys._
import scala.collection.mutable import scala.collection.mutable
import scala.collection.JavaConverters._ import scala.collection.JavaConverters._
import scala.collection.mutable.ArrayBuffer
import scala.util.Try import scala.util.Try
import scalaz.{ \/-, -\/ } import scalaz.{ \/-, -\/ }
@ -258,6 +259,40 @@ object Tasks {
private def createLogger() = new TermDisplay(new OutputStreamWriter(System.err)) private def createLogger() = new TermDisplay(new OutputStreamWriter(System.err))
private lazy val globalPluginPattern = {
val props = sys.props.toMap
val extraProps = new ArrayBuffer[(String, String)]
def addUriProp(key: String): Unit =
for (b <- props.get(key)) {
val uri = new File(b).toURI.toString
extraProps += s"$key.uri" -> uri
}
addUriProp("sbt.global.base")
addUriProp("user.home")
// FIXME get the 0.13 automatically?
val s = s"$${sbt.global.base.uri-$${user.home.uri}/.sbt/0.13}/plugins/target/resolution-cache/" +
"[organization]/[module](/scala_[scalaVersion])(/sbt_[sbtVersion])/[revision]/resolved.xml.[ext]"
val p = PropertiesPattern.parse(s) match {
case -\/(err) =>
throw new Exception(s"Cannot parse pattern $s: $err")
case \/-(p) =>
p
}
p.substituteProperties(props ++ extraProps) match {
case -\/(err) =>
throw new Exception(err)
case \/-(p) =>
p
}
}
def resolutionTask( def resolutionTask(
sbtClassifiers: Boolean = false sbtClassifiers: Boolean = false
) = Def.task { ) = Def.task {
@ -400,9 +435,8 @@ object Tasks {
log.info(s" ${p.module}:${p.version}") log.info(s" ${p.module}:${p.version}")
} }
val globalPluginsRepo = IvyRepository( val globalPluginsRepo = IvyRepository.fromPattern(
new File(sys.props("user.home") + "/.sbt/0.13/plugins/target/resolution-cache/").toURI.toString + globalPluginPattern,
"[organization]/[module](/scala_[scalaVersion])(/sbt_[sbtVersion])/[revision]/resolved.xml.[ext]",
withChecksums = false, withChecksums = false,
withSignatures = false, withSignatures = false,
withArtifacts = false withArtifacts = false
@ -410,8 +444,30 @@ object Tasks {
val interProjectRepo = InterProjectRepository(interProjectDependencies) val interProjectRepo = InterProjectRepository(interProjectDependencies)
val internalSbtScalaProvider = appConfiguration.value.provider.scalaProvider
val internalSbtScalaJarsRepo = SbtScalaJarsRepository(
so, // this seems plain wrong - this assumes that the scala org of the project is the same
// as the one that started SBT. This will scrap the scala org specific JARs by the ones
// that booted SBT, even if the latter come from the standard org.scala-lang org.
// But SBT itself does it this way, and not doing so may make two different versions
// of the scala JARs land in the classpath...
internalSbtScalaProvider.version(),
internalSbtScalaProvider.jars()
)
val ivyHome = sys.props.getOrElse(
"ivy.home",
new File(sys.props("user.home")).toURI.getPath + ".ivy2"
)
val sbtIvyHome = sys.props.getOrElse(
"sbt.ivy.home",
ivyHome
)
val ivyProperties = Map( val ivyProperties = Map(
"ivy.home" -> (new File(sys.props("user.home")).toURI.getPath + ".ivy2") "ivy.home" -> ivyHome,
"sbt.ivy.home" -> sbtIvyHome
) ++ sys.props ) ++ sys.props
val useSbtCredentials = coursierUseSbtCredentials.value val useSbtCredentials = coursierUseSbtCredentials.value
@ -479,7 +535,7 @@ object Tasks {
} }
} }
val internalRepositories = Seq(globalPluginsRepo, interProjectRepo) val internalRepositories = Seq(globalPluginsRepo, interProjectRepo, internalSbtScalaJarsRepo)
val repositories = val repositories =
internalRepositories ++ internalRepositories ++

View File

@ -0,0 +1,13 @@
scalaVersion := "2.11.8"
libraryDependencies += ("com.rengwuxian.materialedittext" % "library" % "2.1.4")
.exclude("com.android.support", "support-v4")
.exclude("com.android.support", "support-annotations")
.exclude("com.android.support", "appcompat-v7")
coursierCachePolicies := {
if (sys.props("os.name").startsWith("Windows"))
coursierCachePolicies.value
else
Seq(coursier.CachePolicy.ForceDownload)
}

View File

@ -0,0 +1,11 @@
{
val pluginVersion = sys.props.getOrElse(
"plugin.version",
throw new RuntimeException(
"""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin
)
)
addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion)
}

View File

@ -0,0 +1,6 @@
import java.io.File
import java.nio.file.Files
object Main extends App {
Files.write(new File("output").toPath, "OK".getBytes("UTF-8"))
}

View File

@ -0,0 +1,3 @@
$ delete output
> run
$ exists output

View File

@ -0,0 +1,8 @@
scalaVersion := appConfiguration.value.provider.scalaProvider.version
coursierCachePolicies := {
if (sys.props("os.name").startsWith("Windows"))
coursierCachePolicies.value
else
Seq(coursier.CachePolicy.ForceDownload)
}

View File

@ -0,0 +1,11 @@
{
val pluginVersion = sys.props.getOrElse(
"plugin.version",
throw new RuntimeException(
"""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin
)
)
addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion)
}

View File

@ -0,0 +1,43 @@
import java.io.File
import java.nio.file.Files
object Main extends App {
val cp = new collection.mutable.ArrayBuffer[File]
def buildCp(loader: ClassLoader): Unit =
if (loader != null) {
loader match {
case u: java.net.URLClassLoader =>
cp ++= u.getURLs
.map(_.toURI)
.map(new File(_))
case _ =>
}
buildCp(loader.getParent)
}
buildCp(Thread.currentThread().getContextClassLoader)
val sbtBase = new File(sys.props.getOrElse(
"sbt.global.base",
sys.props("user.home") + "/.sbt"
))
val prefix = new File(sbtBase, "boot").getAbsolutePath
def fromBootAndUnique(name: String): Unit = {
val jars = cp.filter(_.getName.startsWith(name)).distinct
assert(jars.length == 1, s"Found 0 or multiple JARs for $name: $jars")
val Seq(jar) = jars
assert(jar.getAbsolutePath.startsWith(prefix), s"JAR for $name ($jar) not under $prefix")
}
fromBootAndUnique("scala-library")
fromBootAndUnique("scala-reflect")
fromBootAndUnique("scala-compiler")
Files.write(new File("output").toPath, "OK".getBytes("UTF-8"))
}

View File

@ -0,0 +1,3 @@
$ delete output
> run
$ exists output

View File

@ -3,7 +3,7 @@ addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.11")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.1.0") addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.1.0")
addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.2") addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.2")
addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.0-M12") addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.0-M13")
addSbtPlugin("com.typesafe.sbt" % "sbt-proguard" % "0.2.2") addSbtPlugin("com.typesafe.sbt" % "sbt-proguard" % "0.2.2")
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.9") addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.9")
libraryDependencies += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value libraryDependencies += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value

View File

@ -0,0 +1,70 @@
package coursier.test
import utest._
import coursier.core.Authentication
import coursier.maven.MavenRepository
object HttpAuthenticationTests extends TestSuite {
val tests = TestSuite {
'httpAuthentication - {
// requires an authenticated HTTP server to be running on localhost:8080 with user 'user'
// and password 'pass'
val address = "localhost:8080"
val user = "user"
val password = "pass"
def printErrorMessage() =
Console.err.println(
Console.RED +
s"HTTP authentication tests require a running HTTP server on $address, requiring " +
s"basic authentication with user '$user' and password '$password', serving the right " +
"files.\n" + Console.RESET +
"Run one from the coursier sources with\n" +
" ./coursier launch -r http://dl.bintray.com/scalaz/releases " +
"io.get-coursier:simple-web-server_2.11:1.0.0-M12 -- " +
"-d tests/jvm/src/test/resources/test-repo/http/abc.com -u user -P pass -r realm -v"
)
* - {
// no authentication -> should fail
val failed = try {
CacheFetchTests.check(
MavenRepository(
s"http://$address"
)
)
printErrorMessage()
false
} catch {
case e: Throwable =>
true
}
assert(failed)
}
* - {
// with authentication -> should work
try {
CacheFetchTests.check(
MavenRepository(
s"http://$address",
authentication = Some(Authentication(user, password))
)
)
} catch {
case e: Throwable =>
printErrorMessage()
throw e
}
}
}
}
}

View File

@ -13,55 +13,55 @@ import scala.util.Try
object CacheFetchTests extends TestSuite { object CacheFetchTests extends TestSuite {
val tests = TestSuite { def check(extraRepo: Repository): Unit = {
def check(extraRepo: Repository): Unit = { val tmpDir = Files.createTempDirectory("coursier-cache-fetch-tests").toFile
val tmpDir = Files.createTempDirectory("coursier-cache-fetch-tests").toFile def cleanTmpDir() = {
def delete(f: File): Boolean =
if (f.isDirectory) {
val removedContent = Option(f.listFiles()).toSeq.flatten.map(delete).forall(x => x)
val removedDir = f.delete()
def cleanTmpDir() = { removedContent && removedDir
def delete(f: File): Boolean = } else
if (f.isDirectory) { f.delete()
val removedContent = Option(f.listFiles()).toSeq.flatten.map(delete).forall(x => x)
val removedDir = f.delete()
removedContent && removedDir if (!delete(tmpDir))
} else Console.err.println(s"Warning: unable to remove temporary directory $tmpDir")
f.delete()
if (!delete(tmpDir))
Console.err.println(s"Warning: unable to remove temporary directory $tmpDir")
}
val res = try {
val fetch = Fetch.from(
Seq(
extraRepo,
MavenRepository("https://repo1.maven.org/maven2")
),
Cache.fetch(
tmpDir
)
)
val startRes = Resolution(
Set(
Dependency(
Module("com.github.alexarchambault", "coursier_2.11"), "1.0.0-M9-test"
)
)
)
startRes.process.run(fetch).run
} finally {
cleanTmpDir()
}
val errors = res.errors
assert(errors.isEmpty)
} }
val res = try {
val fetch = Fetch.from(
Seq(
extraRepo,
MavenRepository("https://repo1.maven.org/maven2")
),
Cache.fetch(
tmpDir
)
)
val startRes = Resolution(
Set(
Dependency(
Module("com.github.alexarchambault", "coursier_2.11"), "1.0.0-M9-test"
)
)
)
startRes.process.run(fetch).run
} finally {
cleanTmpDir()
}
val errors = res.errors
assert(errors.isEmpty)
}
val tests = TestSuite {
// using scala-test would allow to put the below comments in the test names... // using scala-test would allow to put the below comments in the test names...
* - { * - {
@ -84,64 +84,6 @@ object CacheFetchTests extends TestSuite {
check(MavenRepository(s"${TestprotocolHandler.protocol}://foo/")) check(MavenRepository(s"${TestprotocolHandler.protocol}://foo/"))
} }
} }
'httpAuthentication - {
// requires an authenticated HTTP server to be running on localhost:8080 with user 'user'
// and password 'pass'
val address = "localhost:8080"
val user = "user"
val password = "pass"
def printErrorMessage() =
Console.err.println(
Console.RED +
s"HTTP authentication tests require a running HTTP server on $address, requiring " +
s"basic authentication with user '$user' and password '$password', serving the right " +
"files.\n" + Console.RESET +
"Run one from the coursier sources with\n" +
" ./coursier launch -r http://dl.bintray.com/scalaz/releases " +
"io.get-coursier:simple-web-server_2.11:1.0.0-M12 -- " +
"-d tests/jvm/src/test/resources/test-repo/http/abc.com -u user -P pass -r realm -v"
)
* - {
// no authentication -> should fail
val failed = try {
check(
MavenRepository(
s"http://$address"
)
)
printErrorMessage()
false
} catch {
case e: Throwable =>
true
}
assert(failed)
}
* - {
// with authentication -> should work
try {
check(
MavenRepository(
s"http://$address",
authentication = Some(Authentication(user, password))
)
)
} catch {
case e: Throwable =>
printErrorMessage()
throw e
}
}
}
} }
} }