diff --git a/.ci/travis.sh b/.ci/travis.sh
index 544e3214b..f52120f17 100755
--- a/.ci/travis.sh
+++ b/.ci/travis.sh
@@ -28,7 +28,7 @@ function isMasterOrDevelop() {
}
# Required for ~/.ivy2/local repo tests
-~/sbt coreJVM/publishLocal http-server/publishLocal
+~/sbt ++2.11.8 coreJVM/publishLocal http-server/publishLocal
# Required for HTTP authentication tests
./coursier launch \
@@ -43,9 +43,33 @@ function isMasterOrDevelop() {
SBT_COMMANDS="compile test it:test"
+RUN_SHADING_TESTS=1
+
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 plugin/scripted"
+
+ if [ "$RUN_SHADING_TESTS" = 1 ]; then
+ # for the shading scripted test
+ sudo cp coursier /usr/local/bin/
+
+ JARJAR_VERSION=1.0.1-coursier-SNAPSHOT
+
+ if [ ! -d "$HOME/.m2/repository/org/anarres/jarjar/jarjar-core/$JARJAR_VERSION" ]; then
+ git clone https://github.com/alexarchambault/jarjar.git
+ cd jarjar
+ if ! grep -q "^version=$JARJAR_VERSION\$" gradle.properties; then
+ echo "Expected jarjar version not found" 1>&2
+ exit 1
+ fi
+ git checkout 249c8dbb970f8
+ ./gradlew :jarjar-core:install
+ cd ..
+ rm -rf jarjar
+ fi
+
+ SBT_COMMANDS="$SBT_COMMANDS plugin/publishLocal sbt-shading/scripted"
+ fi
fi
SBT_COMMANDS="$SBT_COMMANDS tut coreJVM/mimaReportBinaryIssues cache/mimaReportBinaryIssues"
diff --git a/.travis.yml b/.travis.yml
index 427805666..b9d531540 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ script:
# - bash <(curl -s https://codecov.io/bash)
matrix:
include:
- - env: TRAVIS_SCALA_VERSION=2.12.0 PUBLISH=1
+ - env: TRAVIS_SCALA_VERSION=2.12.1 PUBLISH=1
os: linux
jdk: oraclejdk8
- env: TRAVIS_SCALA_VERSION=2.11.8 PUBLISH=1
@@ -36,3 +36,9 @@ env:
branches:
only:
- master
+cache:
+ directories:
+ - $HOME/.m2
+ - $HOME/.ivy2/cache
+ - $HOME/.sbt
+# Not adding $HOME/.coursier, we check that sbt-coursier works fine with an initially empty cache
diff --git a/appveyor.yml b/appveyor.yml
index 6013b49bc..5a7cad557 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -14,15 +14,24 @@ install:
- cmd: SET PATH=C:\sbt\sbt\bin;%JAVA_HOME%\bin;%PATH%
- cmd: SET SBT_OPTS=-XX:MaxPermSize=2g -Xmx4g
- cmd: SET COURSIER_NO_TERM=1
+ - ps: |
+ if (!(Test-Path 'C:\Users\appveyor\.m2\repository\org\anarres\jarjar\jarjar-core\1.0.1-coursier-SNAPSHOT')) {
+ iex 'git clone https://github.com/alexarchambault/jarjar'
+ Set-Location -Path jarjar
+ iex 'git checkout 249c8dbb970f8'
+ iex './gradlew.bat :jarjar-core:install'
+ Set-Location -Path ..
+ }
build_script:
- sbt ++2.11.8 clean compile coreJVM/publishLocal http-server/publishLocal
- sbt ++2.10.6 clean compile
- sbt ++2.10.6 coreJVM/publishLocal cache/publishLocal # to make the scripted tests happy
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 }
- - sbt ++2.12.0 testsJVM/test testsJVM/it:test # Would node be around for testsJS/test?
+ - sbt ++2.12.1 testsJVM/test testsJVM/it:test # Would node be around for testsJS/test?
- sbt ++2.11.8 testsJVM/test testsJVM/it:test
- - sbt ++2.10.6 testsJVM/test testsJVM/it:test plugin/scripted
+ - sbt ++2.10.6 testsJVM/test testsJVM/it:test plugin/scripted plugin/publishLocal sbt-shading/scripted
cache:
- - C:\Users\appveyor\.ivy2
+ - C:\Users\appveyor\.ivy2\cache
+ - C:\Users\appveyor\.m2
- C:\Users\appveyor\.sbt
diff --git a/build.sbt b/build.sbt
index b55aa8e2f..e89a7febb 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,137 +1,29 @@
import java.io.FileOutputStream
-import com.typesafe.tools.mima.plugin.MimaPlugin.mimaDefaultSettings
-
-val binaryCompatibilityVersion = "1.0.0-M7"
+val binaryCompatibilityVersion = "1.0.0-M14"
+val binaryCompatibility212Version = "1.0.0-M15"
lazy val IntegrationTest = config("it") extend Test
-lazy val releaseSettings = Seq(
- publishMavenStyle := true,
- licenses := Seq("Apache 2.0" -> url("http://opensource.org/licenses/Apache-2.0")),
- homepage := Some(url("https://github.com/alexarchambault/coursier")),
- scmInfo := Some(ScmInfo(
- url("https://github.com/alexarchambault/coursier.git"),
- "scm:git:github.com/alexarchambault/coursier.git",
- Some("scm:git:git@github.com:alexarchambault/coursier.git")
- )),
- pomExtra := {
-
-
- alexarchambault
- Alexandre Archambault
- https://github.com/alexarchambault
-
-
- },
- publishTo := {
- val nexus = "https://oss.sonatype.org/"
- if (isSnapshot.value)
- Some("snapshots" at nexus + "content/repositories/snapshots")
- else
- Some("releases" at nexus + "service/local/staging/deploy/maven2")
- },
- credentials ++= {
- Seq("SONATYPE_USER", "SONATYPE_PASS").map(sys.env.get) match {
- case Seq(Some(user), Some(pass)) =>
- Seq(Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", user, pass))
- case _ =>
- Seq()
- }
- }
-)
-
-lazy val noPublishSettings = Seq(
- publish := (),
- publishLocal := (),
- publishArtifact := false
-)
-
-def noPublishForScalaVersionSettings(sbv: String*) = Seq(
- publish := {
- if (sbv.contains(scalaBinaryVersion.value))
- ()
- else
- publish.value
- },
- publishLocal := {
- if (sbv.contains(scalaBinaryVersion.value))
- ()
- else
- publishLocal.value
- },
- publishArtifact := {
- if (sbv.contains(scalaBinaryVersion.value))
- false
- else
- publishArtifact.value
- }
-)
-
-lazy val scalaVersionAgnosticCommonSettings = Seq(
- organization := "io.get-coursier",
- resolvers ++= Seq(
- "Scalaz Bintray Repo" at "http://dl.bintray.com/scalaz/releases",
- Resolver.sonatypeRepo("releases")
- ),
- scalacOptions ++= {
- scalaBinaryVersion.value match {
- case "2.10" | "2.11" =>
- Seq("-target:jvm-1.6")
- case _ =>
- Seq()
- }
- },
- javacOptions ++= {
- scalaBinaryVersion.value match {
- case "2.10" | "2.11" =>
- Seq(
- "-source", "1.6",
- "-target", "1.6"
- )
- case _ =>
- Seq()
- }
- },
- javacOptions in Keys.doc := Seq()
-) ++ releaseSettings
-
-lazy val commonSettings = scalaVersionAgnosticCommonSettings ++ Seq(
- scalaVersion := "2.11.8",
- crossScalaVersions := Seq("2.12.0", "2.11.8", "2.10.6"),
- libraryDependencies ++= {
- if (scalaBinaryVersion.value == "2.10")
- Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full))
- else
- Seq()
- }
-)
-
-val scalazVersion = "7.2.7"
+lazy val scalazVersion = "7.2.8"
lazy val core = crossProject
- .settings(commonSettings: _*)
- .settings(mimaDefaultSettings: _*)
+ .settings(commonSettings)
+ .settings(mimaPreviousArtifactSettings)
.settings(
name := "coursier",
libraryDependencies ++= Seq(
"org.scalaz" %%% "scalaz-core" % scalazVersion,
"com.lihaoyi" %%% "fastparse" % "0.4.2"
),
- mimaPreviousArtifacts := {
- scalaBinaryVersion.value match {
- case "2.10" | "2.11" =>
- Set("com.github.alexarchambault" %% moduleName.value % binaryCompatibilityVersion)
- case _ =>
- Set()
- }
- },
mimaBinaryIssueFilters ++= {
import com.typesafe.tools.mima.core._
Seq(
- // Since 1.0.0-M15
- // reworked profile activation
+ ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.package#Resolution.apply$default$9"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.package#Resolution.apply"),
+ ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.core.Resolution.copy$default$9"),
+ ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.core.Resolution.copyWithCache$default$8"),
ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.core.Resolution.copy"),
ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.core.Resolution.profileActivation"),
ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.core.Resolution.copyWithCache"),
@@ -141,81 +33,18 @@ lazy val core = crossProject
ProblemFilters.exclude[MissingTypesProblem]("coursier.core.Activation$"),
ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.core.Activation.apply"),
ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.core.Resolution.profiles"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.core.Resolution.apply"),
- // Since 1.0.0-M13
- // reworked VersionConstraint
- ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Interval"),
- ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Preferred"),
- ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Preferred$"),
- ProblemFilters.exclude[MissingClassProblem]("coursier.core.VersionConstraint$Interval$"),
- ProblemFilters.exclude[FinalClassProblem]("coursier.core.VersionConstraint"),
- ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.core.VersionConstraint.repr"),
- ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.core.VersionConstraint.this"),
- // Extra `actualVersion` field in `Project`
- ProblemFilters.exclude[MissingTypesProblem]("coursier.core.Project$"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.core.Project.apply"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.core.Project.copy"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.core.Project.this"),
- // Reworked Ivy pattern handling
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.pattern"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.copy"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.properties"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.parts"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.substitute"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.this"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.substituteProperties"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.propertyRegex"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.apply"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.variableRegex"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.Pattern.optionalPartRegex"),
- ProblemFilters.exclude[MissingClassProblem]("coursier.ivy.Pattern$PatternPart$Literal$"),
- ProblemFilters.exclude[MissingClassProblem]("coursier.ivy.Pattern$PatternPart"),
- ProblemFilters.exclude[MissingClassProblem]("coursier.ivy.Pattern$PatternPart$"),
- ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.ivy.IvyRepository.apply"),
- ProblemFilters.exclude[MissingClassProblem]("coursier.ivy.Pattern$PatternPart$Optional$"),
- ProblemFilters.exclude[MissingClassProblem]("coursier.ivy.Pattern$PatternPart$Literal"),
- ProblemFilters.exclude[MissingClassProblem]("coursier.ivy.Pattern$PatternPart$Optional"),
- ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.ivy.IvyRepository.pattern"),
- ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.ivy.IvyRepository.copy"),
- ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.ivy.IvyRepository.properties"),
- ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.ivy.IvyRepository.metadataPattern"),
- ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.ivy.IvyRepository.this"),
- ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.util.Parse.repository"),
- // Since 1.0.0-M12
- // Extra `authentication` field
- ProblemFilters.exclude[MissingMethodProblem]("coursier.core.Artifact.apply"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.core.Artifact.copy"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.core.Artifact.this"),
- ProblemFilters.exclude[MissingTypesProblem]("coursier.ivy.IvyRepository$"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.ivy.IvyRepository.apply"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.ivy.IvyRepository.copy"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.ivy.IvyRepository.this"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.maven.MavenRepository.copy"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.maven.MavenRepository.this"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.maven.MavenSource.apply"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.maven.MavenRepository.apply"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.maven.MavenSource.copy"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.maven.MavenSource.this"),
- // Since 1.0.0-M11
- // Extra parameter with default value added, problem for forward compatibility only
- ProblemFilters.exclude[MissingMethodProblem]("coursier.core.ResolutionProcess.next"),
- // method made final (for - non critical - tail recursion)
- ProblemFilters.exclude[FinalMethodProblem]("coursier.core.ResolutionProcess.next"),
- // Since 1.0.0-M10
- ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.core.Resolution.withParentConfigurations"),
- // New singleton object, problem for forward compatibility only
- ProblemFilters.exclude[MissingTypesProblem]("coursier.maven.MavenSource$")
+ ProblemFilters.exclude[DirectMissingMethodProblem]("coursier.core.Resolution.apply")
)
}
)
.jvmSettings(
libraryDependencies ++=
Seq(
- "org.jsoup" % "jsoup" % "1.9.2"
+ "org.jsoup" % "jsoup" % "1.10.2"
) ++ {
if (scalaBinaryVersion.value == "2.10") Seq()
else Seq(
- "org.scala-lang.modules" %% "scala-xml" % "1.0.5"
+ "org.scala-lang.modules" %% "scala-xml" % "1.0.6"
)
},
resourceGenerators.in(Compile) += {
@@ -260,10 +89,10 @@ lazy val `fetch-js` = project
lazy val tests = crossProject
.dependsOn(core)
- .settings(commonSettings: _*)
- .settings(noPublishSettings: _*)
+ .settings(commonSettings)
+ .settings(noPublishSettings)
.configs(IntegrationTest)
- .settings(Defaults.itSettings: _*)
+ .settings(Defaults.itSettings)
.settings(
name := "coursier-tests",
libraryDependencies += {
@@ -275,7 +104,7 @@ lazy val tests = crossProject
"org.scala-lang.modules" %% "scala-async" % asyncVersion % "provided"
},
- libraryDependencies += "com.lihaoyi" %%% "utest" % "0.4.4" % "test",
+ libraryDependencies += "com.lihaoyi" %%% "utest" % "0.4.5" % "test",
unmanagedResourceDirectories in Test += (baseDirectory in LocalRootProject).value / "tests" / "shared" / "src" / "test" / "resources",
testFrameworks += new TestFramework("utest.runner.Framework")
)
@@ -289,70 +118,19 @@ lazy val testsJs = tests.js.dependsOn(`fetch-js` % "test")
lazy val cache = project
.dependsOn(coreJvm)
.settings(commonSettings)
- .settings(mimaDefaultSettings)
+ .settings(mimaPreviousArtifactSettings)
.settings(
name := "coursier-cache",
libraryDependencies += "org.scalaz" %% "scalaz-concurrent" % scalazVersion,
- mimaPreviousArtifacts := {
- scalaBinaryVersion.value match {
- case "2.10" | "2.11" =>
- Set("com.github.alexarchambault" %% moduleName.value % binaryCompatibilityVersion)
- case _ =>
- Set()
- }
- },
mimaBinaryIssueFilters ++= {
import com.typesafe.tools.mima.core._
Seq(
- // Since 1.0.0-M13
- ProblemFilters.exclude[MissingMethodProblem]("coursier.Cache.file"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.Cache.fetch"),
- // Since 1.0.0-M12
- // Remove deprecated / unused helper method
- ProblemFilters.exclude[MissingMethodProblem]("coursier.Cache.readFully"),
- // Since 1.0.0-M11
- // Add constructor parameter on FileError - shouldn't be built by users anyway
- ProblemFilters.exclude[MissingMethodProblem]("coursier.FileError.this"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.FileError#Recoverable.this"),
- // Since 1.0.0-M10
- // methods that should have been private anyway
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay.update"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay.fallbackMode_="),
- // cache argument type changed from `Seq[(String, File)]` to `File`
- ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.Cache.file"),
- ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.Cache.fetch"),
- ProblemFilters.exclude[IncompatibleResultTypeProblem]("coursier.Cache.default"),
- ProblemFilters.exclude[IncompatibleMethTypeProblem]("coursier.Cache.validateChecksum"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.Cache.defaultBase"),
- // New methdos in Cache.Logger
- ProblemFilters.exclude[MissingMethodProblem]("coursier.Cache#Logger.checkingUpdates"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.Cache#Logger.checkingUpdatesResult"),
- // Better overload of Cache.Logger.downloadLength, deprecate previous one
- ProblemFilters.exclude[MissingMethodProblem]("coursier.Cache#Logger.downloadLength"),
- // Changes to private class TermDisplay#Info
- ProblemFilters.exclude[MissingClassProblem]("coursier.TermDisplay$Info$"),
- ProblemFilters.exclude[AbstractClassProblem]("coursier.TermDisplay$Info"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.downloaded"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.productElement"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.productArity"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.canEqual"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.length"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.display"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.fraction"),
- // Since 1.0.0-M9
- // Added an optional extra parameter to FileError.NotFound - only
- // its unapply method should break compatibility at the source level.
- ProblemFilters.exclude[MissingMethodProblem]("coursier.FileError#NotFound.copy"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.FileError#NotFound.this"),
- ProblemFilters.exclude[MissingTypesProblem]("coursier.FileError$NotFound$"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.FileError#NotFound.apply"),
- // Since 1.0.0-M8
- ProblemFilters.exclude[MissingTypesProblem]("coursier.TermDisplay$Info$"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.apply"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.copy"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.pct"),
- ProblemFilters.exclude[MissingMethodProblem]("coursier.TermDisplay#Info.this")
+ ProblemFilters.exclude[MissingClassProblem]("coursier.TermDisplay$Message$Stop$"),
+ ProblemFilters.exclude[MissingClassProblem]("coursier.TermDisplay$Message"),
+ ProblemFilters.exclude[MissingClassProblem]("coursier.TermDisplay$Message$"),
+ ProblemFilters.exclude[MissingClassProblem]("coursier.TermDisplay$Message$Update$"),
+ ProblemFilters.exclude[MissingClassProblem]("coursier.TermDisplay$UpdateDisplayThread")
)
}
)
@@ -384,7 +162,7 @@ lazy val cli = project
name := "coursier-cli",
libraryDependencies ++= {
if (scalaBinaryVersion.value == "2.11")
- Seq("com.github.alexarchambault" %% "case-app" % "1.1.2")
+ Seq("com.github.alexarchambault" %% "case-app" % "1.1.3")
else
Seq()
},
@@ -512,7 +290,7 @@ lazy val web = project
libraryDependencies ++= {
if (scalaBinaryVersion.value == "2.11")
Seq(
- "be.doeraene" %%% "scalajs-jquery" % "0.9.0",
+ "be.doeraene" %%% "scalajs-jquery" % "0.9.1",
"com.github.japgolly.scalajs-react" %%% "core" % "0.9.0"
)
else
@@ -550,28 +328,20 @@ lazy val doc = project
// Don't try to compile that if you're not in 2.10
lazy val plugin = project
.dependsOn(coreJvm, cache)
- .settings(scalaVersionAgnosticCommonSettings)
- .settings(noPublishForScalaVersionSettings("2.11", "2.12"))
+ .settings(pluginSettings)
.settings(
- name := "sbt-coursier",
- sbtPlugin := (scalaBinaryVersion.value == "2.10"),
- resolvers ++= Seq(
- // added so that 2.10 artifacts of the other modules can be found by
- // the too-naive-for-now inter-project resolver of the coursier SBT plugin
- Resolver.sonatypeRepo("snapshots"),
- // added for sbt-scripted to be fine even with ++2.11.x
- Resolver.typesafeIvyRepo("releases")
- )
+ name := "sbt-coursier"
)
- .settings(ScriptedPlugin.scriptedSettings)
+
+// Don't try to compile that if you're not in 2.10
+lazy val `sbt-shading` = project
+ .dependsOn(plugin)
+ .settings(pluginSettings)
.settings(
- scriptedLaunchOpts ++= Seq(
- "-Xmx1024M",
- "-XX:MaxPermSize=256M",
- "-Dplugin.version=" + version.value,
- "-Dsbttest.base=" + (sourceDirectory.value / "sbt-test").getAbsolutePath
- ),
- scriptedBufferLog := false
+ // Warning: this version doesn't handle well class names with '$'s
+ // (so basically any Scala library)
+ // See https://github.com/shevek/jarjar/pull/4
+ libraryDependencies += "org.anarres.jarjar" % "jarjar-core" % "1.0.0"
)
val http4sVersion = "0.8.6"
@@ -587,8 +357,8 @@ lazy val `http-server` = project
Seq(
"org.http4s" %% "http4s-blazeserver" % http4sVersion,
"org.http4s" %% "http4s-dsl" % http4sVersion,
- "org.slf4j" % "slf4j-nop" % "1.7.21",
- "com.github.alexarchambault" %% "case-app" % "1.1.2"
+ "org.slf4j" % "slf4j-nop" % "1.7.22",
+ "com.github.alexarchambault" %% "case-app" % "1.1.3"
)
else
Seq()
@@ -606,10 +376,159 @@ lazy val okhttp = project
)
lazy val `coursier` = project.in(file("."))
- .aggregate(coreJvm, coreJs, `fetch-js`, testsJvm, testsJs, cache, bootstrap, cli, plugin, web, doc, `http-server`, okhttp)
+ .aggregate(
+ coreJvm,
+ coreJs,
+ `fetch-js`,
+ testsJvm,
+ testsJs,
+ cache,
+ bootstrap,
+ cli,
+ plugin,
+ `sbt-shading`,
+ web,
+ doc,
+ `http-server`,
+ okhttp
+ )
.settings(commonSettings)
.settings(noPublishSettings)
.settings(releaseSettings)
.settings(
moduleName := "coursier-root"
)
+
+lazy val releaseSettings = Seq(
+ publishMavenStyle := true,
+ licenses := Seq("Apache 2.0" -> url("http://opensource.org/licenses/Apache-2.0")),
+ homepage := Some(url("https://github.com/alexarchambault/coursier")),
+ scmInfo := Some(ScmInfo(
+ url("https://github.com/alexarchambault/coursier.git"),
+ "scm:git:github.com/alexarchambault/coursier.git",
+ Some("scm:git:git@github.com:alexarchambault/coursier.git")
+ )),
+ pomExtra := {
+
+
+ alexarchambault
+ Alexandre Archambault
+ https://github.com/alexarchambault
+
+
+ },
+ publishTo := {
+ val nexus = "https://oss.sonatype.org/"
+ if (isSnapshot.value)
+ Some("snapshots" at nexus + "content/repositories/snapshots")
+ else
+ Some("releases" at nexus + "service/local/staging/deploy/maven2")
+ },
+ credentials ++= {
+ Seq("SONATYPE_USER", "SONATYPE_PASS").map(sys.env.get) match {
+ case Seq(Some(user), Some(pass)) =>
+ Seq(Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", user, pass))
+ case _ =>
+ Seq()
+ }
+ }
+)
+
+lazy val noPublishSettings = Seq(
+ publish := (),
+ publishLocal := (),
+ publishArtifact := false
+)
+
+def noPublishForScalaVersionSettings(sbv: String*) = Seq(
+ publish := {
+ if (sbv.contains(scalaBinaryVersion.value))
+ ()
+ else
+ publish.value
+ },
+ publishLocal := {
+ if (sbv.contains(scalaBinaryVersion.value))
+ ()
+ else
+ publishLocal.value
+ },
+ publishArtifact := {
+ if (sbv.contains(scalaBinaryVersion.value))
+ false
+ else
+ publishArtifact.value
+ }
+)
+
+lazy val scalaVersionAgnosticCommonSettings = Seq(
+ organization := "io.get-coursier",
+ resolvers ++= Seq(
+ "Scalaz Bintray Repo" at "http://dl.bintray.com/scalaz/releases",
+ Resolver.sonatypeRepo("releases")
+ ),
+ scalacOptions ++= {
+ scalaBinaryVersion.value match {
+ case "2.10" | "2.11" =>
+ Seq("-target:jvm-1.6")
+ case _ =>
+ Seq()
+ }
+ },
+ javacOptions ++= {
+ scalaBinaryVersion.value match {
+ case "2.10" | "2.11" =>
+ Seq(
+ "-source", "1.6",
+ "-target", "1.6"
+ )
+ case _ =>
+ Seq()
+ }
+ },
+ javacOptions in Keys.doc := Seq()
+) ++ releaseSettings
+
+lazy val commonSettings = scalaVersionAgnosticCommonSettings ++ Seq(
+ scalaVersion := "2.12.1",
+ crossScalaVersions := Seq("2.12.1", "2.11.8", "2.10.6"),
+ libraryDependencies ++= {
+ if (scalaBinaryVersion.value == "2.10")
+ Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full))
+ else
+ Seq()
+ }
+)
+
+lazy val pluginSettings =
+ scalaVersionAgnosticCommonSettings ++
+ noPublishForScalaVersionSettings("2.11", "2.12") ++
+ ScriptedPlugin.scriptedSettings ++
+ Seq(
+ scriptedLaunchOpts ++= Seq(
+ "-Xmx1024M",
+ "-XX:MaxPermSize=256M",
+ "-Dplugin.version=" + version.value,
+ "-Dsbttest.base=" + (sourceDirectory.value / "sbt-test").getAbsolutePath
+ ),
+ scriptedBufferLog := false,
+ sbtPlugin := (scalaBinaryVersion.value == "2.10"),
+ resolvers ++= Seq(
+ // added so that 2.10 artifacts of the other modules can be found by
+ // the too-naive-for-now inter-project resolver of the coursier SBT plugin
+ Resolver.sonatypeRepo("snapshots"),
+ // added for sbt-scripted to be fine even with ++2.11.x
+ Resolver.typesafeIvyRepo("releases")
+ )
+ )
+
+lazy val mimaPreviousArtifactSettings = Seq(
+ mimaPreviousArtifacts := {
+ val version = scalaBinaryVersion.value match {
+ case "2.12" => binaryCompatibility212Version
+ case _ => binaryCompatibilityVersion
+ }
+
+ Set(organization.value %% moduleName.value % version)
+ }
+)
diff --git a/coursier.bat b/coursier.bat
new file mode 100644
index 000000000..194c3aed2
--- /dev/null
+++ b/coursier.bat
@@ -0,0 +1,29 @@
+@REM https://github.com/xerial/sbt-pack/blob/master/src/main/templates/launch-bat.mustache
+@REM would be worth getting more inspiration from
+
+@echo off
+
+SET ERROR_CODE=0
+
+SET LAUNCHER_PATH=%~dp0/coursier
+
+IF NOT EXIST %LAUNCHER_PATH% (
+ bitsadmin /transfer "DownloadCoursierLauncher" https://github.com/alexarchambault/coursier/raw/master/coursier %LAUNCHER_PATH%
+)
+
+SET CMD_LINE_ARGS=%*
+
+java -jar %LAUNCHER_PATH% %CMD_LINE_ARGS%
+
+IF ERRORLEVEL 1 GOTO error
+GOTO end
+
+:error
+SET ERROR_CODE=1
+
+:end
+SET LAUNCHER_PATH=
+SET CMD_LINE_ARGS=
+
+EXIT /B %ERROR_CODE%
+
diff --git a/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala b/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala
index dcf7378c2..c2c04c982 100644
--- a/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala
+++ b/plugin/src/main/scala-2.10/coursier/CoursierPlugin.scala
@@ -38,6 +38,10 @@ object CoursierPlugin extends AutoPlugin {
val coursierDependencyTree = Keys.coursierDependencyTree
val coursierDependencyInverseTree = Keys.coursierDependencyInverseTree
+
+ val coursierArtifacts = Keys.coursierArtifacts
+ val coursierClassifiersArtifacts = Keys.coursierClassifiersArtifacts
+ val coursierSbtClassifiersArtifacts = Keys.coursierSbtClassifiersArtifacts
}
import autoImport._
@@ -51,7 +55,25 @@ object CoursierPlugin extends AutoPlugin {
)
)
- override lazy val projectSettings = Seq(
+ def makeIvyXmlBefore[T](
+ task: TaskKey[T],
+ shadedConfigOpt: Option[(String, String)]
+ ): Setting[Task[T]] =
+ // not 100% sure that make writeFiles below happen before the actions triggered by task.value...
+ task := {
+ val currentProject = {
+ val proj = coursierProject.value
+ val publications = coursierPublications.value
+ proj.copy(publications = publications)
+ }
+ IvyXml.writeFiles(currentProject, shadedConfigOpt, ivySbt.value, streams.value.log)
+ task.value
+ }
+
+ def coursierSettings(
+ shadedConfigOpt: Option[(String, String)],
+ packageConfigs: Seq[(Configuration, String)]
+ ) = Seq(
coursierParallelDownloads := 6,
coursierMaxIterations := 50,
coursierDefaultArtifactType := "",
@@ -68,27 +90,44 @@ object CoursierPlugin extends AutoPlugin {
coursierCredentials := Map.empty,
coursierFallbackDependencies <<= Tasks.coursierFallbackDependenciesTask,
coursierCache := Cache.default,
- update <<= Tasks.updateTask(withClassifiers = false),
+ coursierArtifacts <<= Tasks.artifactFilesOrErrors(withClassifiers = false),
+ coursierClassifiersArtifacts <<= Tasks.artifactFilesOrErrors(
+ withClassifiers = true
+ ),
+ coursierSbtClassifiersArtifacts <<= Tasks.artifactFilesOrErrors(
+ withClassifiers = true,
+ sbtClassifiers = true
+ ),
+ makeIvyXmlBefore(deliverLocalConfiguration, shadedConfigOpt),
+ makeIvyXmlBefore(deliverConfiguration, shadedConfigOpt),
+ update <<= Tasks.updateTask(
+ shadedConfigOpt,
+ withClassifiers = false
+ ),
updateClassifiers <<= Tasks.updateTask(
+ shadedConfigOpt,
withClassifiers = true,
ignoreArtifactErrors = true
),
updateSbtClassifiers in Defaults.TaskGlobal <<= Tasks.updateTask(
+ shadedConfigOpt,
withClassifiers = true,
sbtClassifiers = true,
ignoreArtifactErrors = true
),
coursierProject <<= Tasks.coursierProjectTask,
coursierInterProjectDependencies <<= Tasks.coursierInterProjectDependenciesTask,
- coursierPublications <<= Tasks.coursierPublicationsTask,
+ coursierPublications <<= Tasks.coursierPublicationsTask(packageConfigs: _*),
coursierSbtClassifiersModule <<= classifiersModule in updateSbtClassifiers,
- coursierConfigurations <<= Tasks.coursierConfigurationsTask,
+ coursierConfigurations <<= Tasks.coursierConfigurationsTask(None),
coursierResolution <<= Tasks.resolutionTask(),
coursierSbtClassifiersResolution <<= Tasks.resolutionTask(
sbtClassifiers = true
)
- ) ++
- inConfig(Compile)(treeSettings) ++
- inConfig(Test)(treeSettings)
+ )
-}
+ override lazy val projectSettings = coursierSettings(None, Seq(Compile, Test).map(c => c -> c.name)) ++
+ inConfig(Compile)(treeSettings) ++
+ inConfig(Test)(treeSettings)
+
+}
\ No newline at end of file
diff --git a/plugin/src/main/scala-2.10/coursier/FromSbt.scala b/plugin/src/main/scala-2.10/coursier/FromSbt.scala
index c162efad4..befd22c47 100644
--- a/plugin/src/main/scala-2.10/coursier/FromSbt.scala
+++ b/plugin/src/main/scala-2.10/coursier/FromSbt.scala
@@ -1,6 +1,7 @@
package coursier
-import coursier.ivy.{ IvyXml, IvyRepository }
+import coursier.ivy.IvyRepository
+import coursier.ivy.IvyXml.{ mappings => ivyXmlMappings }
import java.net.{ MalformedURLException, URL }
@@ -71,7 +72,7 @@ object FromSbt {
)
val mapping = module.configurations.getOrElse("compile")
- val allMappings = IvyXml.mappings(mapping)
+ val allMappings = ivyXmlMappings(mapping)
val attributes =
if (module.explicitArtifacts.isEmpty)
diff --git a/plugin/src/main/scala-2.10/coursier/MakeIvyXml.scala b/plugin/src/main/scala-2.10/coursier/IvyXml.scala
similarity index 50%
rename from plugin/src/main/scala-2.10/coursier/MakeIvyXml.scala
rename to plugin/src/main/scala-2.10/coursier/IvyXml.scala
index 45ef60556..b3972ea5e 100644
--- a/plugin/src/main/scala-2.10/coursier/MakeIvyXml.scala
+++ b/plugin/src/main/scala-2.10/coursier/IvyXml.scala
@@ -1,10 +1,62 @@
package coursier
-import scala.xml.{ Node, PrefixedAttribute }
+import coursier.internal.FileUtil
+import org.apache.ivy.core.module.id.ModuleRevisionId
-object MakeIvyXml {
+import scala.collection.JavaConverters._
+import scala.xml.{Node, PrefixedAttribute}
- def apply(project: Project): Node = {
+object IvyXml {
+
+ // These are required for publish to be fine, later on.
+ def writeFiles(
+ currentProject: Project,
+ shadedConfigOpt: Option[(String, String)],
+ ivySbt: sbt.IvySbt,
+ log: sbt.Logger
+ ): Unit = {
+
+ val ivyCacheManager = ivySbt.withIvy(log)(ivy =>
+ ivy.getResolutionCacheManager
+ )
+
+ val ivyModule = ModuleRevisionId.newInstance(
+ currentProject.module.organization,
+ currentProject.module.name,
+ currentProject.version,
+ currentProject.module.attributes.asJava
+ )
+
+ val cacheIvyFile = ivyCacheManager.getResolvedIvyFileInCache(ivyModule)
+ val cacheIvyPropertiesFile = ivyCacheManager.getResolvedIvyPropertiesInCache(ivyModule)
+
+ val printer = new scala.xml.PrettyPrinter(80, 2)
+
+ val content0 = """""" + '\n' +
+ printer.format(content(currentProject, shadedConfigOpt.map(_._2)))
+ cacheIvyFile.getParentFile.mkdirs()
+ log.info(s"Writing Ivy file $cacheIvyFile")
+ FileUtil.write(cacheIvyFile, content0.getBytes("UTF-8"))
+
+ // Just writing an empty file here... Are these only used?
+ cacheIvyPropertiesFile.getParentFile.mkdirs()
+ FileUtil.write(cacheIvyPropertiesFile, Array())
+ }
+
+ def content(project0: Project, shadedConfigOpt: Option[String]): Node = {
+
+ val filterOutDependencies =
+ shadedConfigOpt.toSet[String].flatMap { shadedConfig =>
+ project0
+ .dependencies
+ .collect { case (`shadedConfig`, dep) => dep }
+ }
+
+ val project: Project = project0.copy(
+ dependencies = project0.dependencies.collect {
+ case p @ (_, dep) if !filterOutDependencies(dep) => p
+ }
+ )
val infoAttrs = project.module.attributes.foldLeft[xml.MetaData](xml.Null) {
case (acc, (k, v)) =>
@@ -31,11 +83,12 @@ object MakeIvyXml {
} % infoAttrs
- val confElems = project.configurations.toVector.map {
- case (name, extends0) =>
+ val confElems = project.configurations.toVector.collect {
+ case (name, extends0) if shadedConfigOpt != Some(name) =>
+ val extends1 = shadedConfigOpt.fold(extends0)(c => extends0.filter(_ != c))
val n =
- if (extends0.nonEmpty)
- n % .attributes
+ if (extends1.nonEmpty)
+ n % .attributes
else
n
}
diff --git a/plugin/src/main/scala-2.10/coursier/Keys.scala b/plugin/src/main/scala-2.10/coursier/Keys.scala
index e8b5c5bc7..f2c894163 100644
--- a/plugin/src/main/scala-2.10/coursier/Keys.scala
+++ b/plugin/src/main/scala-2.10/coursier/Keys.scala
@@ -8,6 +8,7 @@ import coursier.core.Publication
import sbt.{ GetClassifiersModule, Resolver, SettingKey, TaskKey }
import scala.concurrent.duration.Duration
+import scalaz.\/
object Keys {
val coursierParallelDownloads = SettingKey[Int]("coursier-parallel-downloads")
@@ -51,4 +52,8 @@ object Keys {
"coursier-dependency-inverse-tree",
"Prints dependencies and transitive dependencies as an inverted tree (dependees as children)"
)
+
+ val coursierArtifacts = TaskKey[Map[Artifact, FileError \/ File]]("coursier-artifacts")
+ val coursierClassifiersArtifacts = TaskKey[Map[Artifact, FileError \/ File]]("coursier-classifiers-artifacts")
+ val coursierSbtClassifiersArtifacts = TaskKey[Map[Artifact, FileError \/ File]]("coursier-sbt-classifiers-artifacts")
}
diff --git a/plugin/src/main/scala-2.10/coursier/Tasks.scala b/plugin/src/main/scala-2.10/coursier/Tasks.scala
index 8f681ff8e..2dbcc116b 100644
--- a/plugin/src/main/scala-2.10/coursier/Tasks.scala
+++ b/plugin/src/main/scala-2.10/coursier/Tasks.scala
@@ -13,7 +13,6 @@ import coursier.util.{ Config, Print }
import org.apache.ivy.core.module.id.ModuleRevisionId
import sbt.{ UpdateReport, Classpaths, Resolver, Def }
-import sbt.Configurations.{ Compile, Test }
import sbt.Keys._
import scala.collection.mutable
@@ -147,7 +146,7 @@ object Tasks {
coursierProject.forAllProjects(state, projects).map(_.values.toVector)
}
- def coursierPublicationsTask: Def.Initialize[sbt.Task[Seq[(String, Publication)]]] =
+ def coursierPublicationsTask(configsMap: (sbt.Configuration, String)*): Def.Initialize[sbt.Task[Seq[(String, Publication)]]] =
(
sbt.Keys.state,
sbt.Keys.thisProjectRef,
@@ -158,17 +157,16 @@ object Tasks {
).map { (state, projectRef, projId, sv, sbv, ivyConfs) =>
val packageTasks = Seq(packageBin, packageSrc, packageDoc)
- val configs = Seq(Compile, Test)
val sbtArtifacts =
for {
pkgTask <- packageTasks
- config <- configs
+ (config, targetConfig) <- configsMap
} yield {
val publish = publishArtifact.in(projectRef).in(pkgTask).in(config).getOrElse(state, false)
if (publish)
Option(artifact.in(projectRef).in(pkgTask).in(config).getOrElse(state, null))
- .map(config.name -> _)
+ .map(targetConfig -> _)
else
None
}
@@ -219,7 +217,7 @@ object Tasks {
sbtArtifactsPublication ++ extraSbtArtifactsPublication
}
- def coursierConfigurationsTask = Def.task {
+ def coursierConfigurationsTask(shadedConfig: Option[(String, String)]) = Def.task {
val configs0 = ivyConfigurations.value.map { config =>
config.name -> config.extendsConfigs.map(_.name)
@@ -238,10 +236,18 @@ object Tasks {
helper(Set(c))
}
- configs0.map {
+ val map = configs0.map {
case (config, _) =>
config -> allExtends(config)
}
+
+ map ++ shadedConfig.toSeq.flatMap {
+ case (baseConfig, shadedConfig) =>
+ Seq(
+ baseConfig -> (map.getOrElse(baseConfig, Set(baseConfig)) + shadedConfig),
+ shadedConfig -> map.getOrElse(shadedConfig, Set(shadedConfig))
+ )
+ }
}
private case class ResolutionCacheKey(
@@ -647,14 +653,155 @@ object Tasks {
}
}
- def updateTask(
+ def artifactFilesOrErrors(
withClassifiers: Boolean,
sbtClassifiers: Boolean = false,
ignoreArtifactErrors: Boolean = false
) = Def.task {
- def grouped[K, V](map: Seq[(K, V)]): Map[K, Seq[V]] =
- map.groupBy { case (k, _) => k }.map {
+ // let's update only one module at once, for a better output
+ // Downloads are already parallel, no need to parallelize further anyway
+ synchronized {
+
+ lazy val cm = coursierSbtClassifiersModule.value
+
+ lazy val projectName = thisProjectRef.value.project
+
+ val parallelDownloads = coursierParallelDownloads.value
+ val artifactsChecksums = coursierArtifactsChecksums.value
+ val cachePolicies = coursierCachePolicies.value
+ val ttl = coursierTtl.value
+ val cache = coursierCache.value
+
+ val log = streams.value.log
+
+ val verbosityLevel = coursierVerbosity.value
+
+ val res = {
+ if (withClassifiers && sbtClassifiers)
+ coursierSbtClassifiersResolution
+ else
+ coursierResolution
+ }.value
+
+ val classifiers =
+ if (withClassifiers)
+ Some {
+ if (sbtClassifiers)
+ cm.classifiers
+ else
+ transitiveClassifiers.value
+ }
+ else
+ None
+
+ val allArtifacts =
+ classifiers match {
+ case None => res.artifacts
+ case Some(cl) => res.classifiersArtifacts(cl)
+ }
+
+ var pool: ExecutorService = null
+ var artifactsLogger: TermDisplay = null
+
+ val printOptionalMessage = verbosityLevel >= 0 && verbosityLevel <= 1
+
+ val artifactFilesOrErrors = try {
+ pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)
+ artifactsLogger = createLogger()
+
+ val artifactFileOrErrorTasks = allArtifacts.toVector.map { a =>
+ def f(p: CachePolicy) =
+ Cache.file(
+ a,
+ cache,
+ p,
+ checksums = artifactsChecksums,
+ logger = Some(artifactsLogger),
+ pool = pool,
+ ttl = ttl
+ )
+
+ cachePolicies.tail
+ .foldLeft(f(cachePolicies.head))(_ orElse f(_))
+ .run
+ .map((a, _))
+ }
+
+ val artifactInitialMessage =
+ if (verbosityLevel >= 0)
+ s"Fetching artifacts of $projectName" +
+ (if (sbtClassifiers) " (sbt classifiers)" else "")
+ else
+ ""
+
+ if (verbosityLevel >= 2)
+ log.info(artifactInitialMessage)
+
+ artifactsLogger.init(if (printOptionalMessage) log.info(artifactInitialMessage))
+
+ Task.gatherUnordered(artifactFileOrErrorTasks).attemptRun match {
+ case -\/(ex) =>
+ ResolutionError.UnknownDownloadException(ex)
+ .throwException()
+ case \/-(l) =>
+ l.toMap
+ }
+ } finally {
+ if (pool != null)
+ pool.shutdown()
+ if (artifactsLogger != null)
+ if ((artifactsLogger.stopDidPrintSomething() && printOptionalMessage) || verbosityLevel >= 2)
+ log.info(
+ s"Fetched artifacts of $projectName" +
+ (if (sbtClassifiers) " (sbt classifiers)" else "")
+ )
+ }
+
+ artifactFilesOrErrors
+ }
+ }
+
+ private def artifactFileOpt(
+ sbtBootJarOverrides: Map[(Module, String), File],
+ artifactFiles: Map[Artifact, File],
+ erroredArtifacts: Set[Artifact],
+ log: sbt.Logger,
+ module: Module,
+ version: String,
+ artifact: Artifact
+ ) = {
+
+ val artifact0 = artifact
+ .copy(attributes = Attributes()) // temporary hack :-(
+
+ // Under some conditions, SBT puts the scala JARs of its own classpath
+ // in the application classpath. Ensuring we return SBT's jars rather than
+ // JARs from the coursier cache, so that a same JAR doesn't land twice in the
+ // application classpath (once via SBT jars, once via coursier cache).
+ val fromBootJars =
+ if (artifact.classifier.isEmpty && artifact.`type` == "jar")
+ sbtBootJarOverrides.get((module, version))
+ else
+ None
+
+ val res = fromBootJars.orElse(artifactFiles.get(artifact0))
+
+ if (res.isEmpty && !erroredArtifacts(artifact0))
+ log.error(s"${artifact.url} not downloaded (should not happen)")
+
+ res
+ }
+
+ def updateTask(
+ shadedConfigOpt: Option[(String, String)],
+ withClassifiers: Boolean,
+ sbtClassifiers: Boolean = false,
+ ignoreArtifactErrors: Boolean = false
+ ) = Def.task {
+
+ def grouped[K, V](map: Seq[(K, V)])(mapKey: K => K): Map[K, Seq[V]] =
+ map.groupBy { case (k, _) => mapKey(k) }.map {
case (k, l) =>
k -> l.map { case (_, v) => v }
}
@@ -677,8 +824,6 @@ object Tasks {
lazy val cm = coursierSbtClassifiersModule.value
- lazy val projectName = thisProjectRef.value.project
-
val currentProject =
if (sbtClassifiers) {
val sv = scalaVersion.value
@@ -699,46 +844,10 @@ object Tasks {
proj.copy(publications = publications)
}
- val ivySbt0 = ivySbt.value
- val ivyCacheManager = ivySbt0.withIvy(streams.value.log)(ivy =>
- ivy.getResolutionCacheManager
- )
-
- val ivyModule = ModuleRevisionId.newInstance(
- currentProject.module.organization,
- currentProject.module.name,
- currentProject.version,
- currentProject.module.attributes.asJava
- )
- val cacheIvyFile = ivyCacheManager.getResolvedIvyFileInCache(ivyModule)
- val cacheIvyPropertiesFile = ivyCacheManager.getResolvedIvyPropertiesInCache(ivyModule)
-
- val parallelDownloads = coursierParallelDownloads.value
- val artifactsChecksums = coursierArtifactsChecksums.value
- val cachePolicies = coursierCachePolicies.value
- val ttl = coursierTtl.value
- val cache = coursierCache.value
-
val log = streams.value.log
val verbosityLevel = coursierVerbosity.value
- // required for publish to be fine, later on
- def writeIvyFiles() = {
- val printer = new scala.xml.PrettyPrinter(80, 2)
-
- val b = new StringBuilder
- b ++= """"""
- b += '\n'
- b ++= printer.format(MakeIvyXml(currentProject))
- cacheIvyFile.getParentFile.mkdirs()
- FileUtil.write(cacheIvyFile, b.result().getBytes("UTF-8"))
-
- // Just writing an empty file here... Are these only used?
- cacheIvyPropertiesFile.getParentFile.mkdirs()
- FileUtil.write(cacheIvyPropertiesFile, "".getBytes("UTF-8"))
- }
-
val res = {
if (withClassifiers && sbtClassifiers)
coursierSbtClassifiersResolution
@@ -748,9 +857,25 @@ object Tasks {
def report = {
- val depsByConfig = grouped(currentProject.dependencies)
+ val depsByConfig = grouped(currentProject.dependencies)(
+ config =>
+ shadedConfigOpt match {
+ case Some((baseConfig, `config`)) =>
+ baseConfig
+ case _ =>
+ config
+ }
+ )
- val configs = coursierConfigurations.value
+ val configs = {
+ val m = coursierConfigurations.value
+ shadedConfigOpt.fold(m) {
+ case (baseConfig, shadedConfig) =>
+ (m - shadedConfig) + (
+ baseConfig -> (m.getOrElse(baseConfig, Set()) - shadedConfig)
+ )
+ }
+ }
if (verbosityLevel >= 2) {
val finalDeps = Config.dependenciesWithConfig(
@@ -775,75 +900,22 @@ object Tasks {
else
None
- val allArtifacts =
- classifiers match {
- case None => res.artifacts
- case Some(cl) => res.classifiersArtifacts(cl)
- }
-
- var pool: ExecutorService = null
- var artifactsLogger: TermDisplay = null
-
- val printOptionalMessage = verbosityLevel >= 0 && verbosityLevel <= 1
-
- val artifactFilesOrErrors = try {
- pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)
- artifactsLogger = createLogger()
-
- val artifactFileOrErrorTasks = allArtifacts.toVector.map { a =>
- def f(p: CachePolicy) =
- Cache.file(
- a,
- cache,
- p,
- checksums = artifactsChecksums,
- logger = Some(artifactsLogger),
- pool = pool,
- ttl = ttl
- )
-
- cachePolicies.tail
- .foldLeft(f(cachePolicies.head))(_ orElse f(_))
- .run
- .map((a, _))
- }
-
- val artifactInitialMessage =
- if (verbosityLevel >= 0)
- s"Fetching artifacts of $projectName" +
- (if (sbtClassifiers) " (sbt classifiers)" else "")
+ val artifactFilesOrErrors0 = (
+ if (withClassifiers) {
+ if (sbtClassifiers)
+ Keys.coursierSbtClassifiersArtifacts
else
- ""
+ Keys.coursierClassifiersArtifacts
+ } else
+ Keys.coursierArtifacts
+ ).value
- if (verbosityLevel >= 2)
- log.info(artifactInitialMessage)
-
- artifactsLogger.init(if (printOptionalMessage) log.info(artifactInitialMessage))
-
- Task.gatherUnordered(artifactFileOrErrorTasks).attemptRun match {
- case -\/(ex) =>
- ResolutionError.UnknownDownloadException(ex)
- .throwException()
- case \/-(l) =>
- l.toMap
- }
- } finally {
- if (pool != null)
- pool.shutdown()
- if (artifactsLogger != null)
- if ((artifactsLogger.stopDidPrintSomething() && printOptionalMessage) || verbosityLevel >= 2)
- log.info(
- s"Fetched artifacts of $projectName" +
- (if (sbtClassifiers) " (sbt classifiers)" else "")
- )
- }
-
- val artifactFiles = artifactFilesOrErrors.collect {
+ val artifactFiles = artifactFilesOrErrors0.collect {
case (artifact, \/-(file)) =>
artifact -> file
}
- val artifactErrors = artifactFilesOrErrors.toVector.collect {
+ val artifactErrors = artifactFilesOrErrors0.toVector.collect {
case (_, -\/(err)) =>
err
}
@@ -858,42 +930,25 @@ object Tasks {
}
// can be non empty only if ignoreArtifactErrors is true
- val erroredArtifacts = artifactFilesOrErrors.collect {
+ val erroredArtifacts = artifactFilesOrErrors0.collect {
case (artifact, -\/(_)) =>
artifact
}.toSet
- def artifactFileOpt(module: Module, version: String, artifact: Artifact) = {
-
- val artifact0 = artifact
- .copy(attributes = Attributes()) // temporary hack :-(
-
- // Under some conditions, SBT puts the scala JARs of its own classpath
- // in the application classpath. Ensuring we return SBT's jars rather than
- // JARs from the coursier cache, so that a same JAR doesn't land twice in the
- // application classpath (once via SBT jars, once via coursier cache).
- val fromBootJars =
- if (artifact.classifier.isEmpty && artifact.`type` == "jar")
- sbtBootJarOverrides.get((module, version))
- else
- None
-
- val res = fromBootJars.orElse(artifactFiles.get(artifact0))
-
- if (res.isEmpty && !erroredArtifacts(artifact0))
- log.error(s"${artifact.url} not downloaded (should not happen)")
-
- res
- }
-
- writeIvyFiles()
-
ToSbt.updateReport(
depsByConfig,
res,
configs,
classifiers,
- artifactFileOpt
+ artifactFileOpt(
+ sbtBootJarOverrides,
+ artifactFiles,
+ erroredArtifacts,
+ log,
+ _,
+ _,
+ _
+ )
)
}
diff --git a/plugin/src/sbt-test/sbt-coursier/from/test b/plugin/src/sbt-test/sbt-coursier/from/test
index 2182f57b0..11e0b3386 100644
--- a/plugin/src/sbt-test/sbt-coursier/from/test
+++ b/plugin/src/sbt-test/sbt-coursier/from/test
@@ -1,3 +1,4 @@
$ delete output
> run
$ exists output
+$ delete shapeless_2.11-2.3.0.jar
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 3af981297..cfb97f581 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,9 +1,9 @@
-addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.8.0")
-addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.13")
+addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.8.2")
+addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.14")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.4.0")
-addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.6")
-addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.0-M14")
+addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.8")
+addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.0-M15-1")
addSbtPlugin("com.typesafe.sbt" % "sbt-proguard" % "0.2.2")
-addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.11")
+addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.13")
libraryDependencies += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value
diff --git a/project/project/plugins.sbt b/project/project/plugins.sbt
index 2617da214..1994c65c9 100644
--- a/project/project/plugins.sbt
+++ b/project/project/plugins.sbt
@@ -1 +1 @@
-addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.0-M14")
+addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.0-M15-1")
diff --git a/sbt-shading/src/main/scala-2.10/coursier/Shading.scala b/sbt-shading/src/main/scala-2.10/coursier/Shading.scala
new file mode 100644
index 000000000..510c479fa
--- /dev/null
+++ b/sbt-shading/src/main/scala-2.10/coursier/Shading.scala
@@ -0,0 +1,152 @@
+package coursier
+
+import java.io.{File, FileInputStream}
+import java.util.jar.JarInputStream
+import java.util.zip.{ZipEntry, ZipInputStream}
+
+import com.tonicsystems.jarjar.classpath.ClassPath
+import com.tonicsystems.jarjar.transform.JarTransformer
+import com.tonicsystems.jarjar.transform.config.ClassRename
+import com.tonicsystems.jarjar.transform.jar.DefaultJarProcessor
+import coursier.core.Orders
+import sbt.file
+
+import scalaz.{\/, \/-}
+
+object Shading {
+
+ // FIXME Also vaguely in cli
+ def zipEntries(zipStream: ZipInputStream): Iterator[ZipEntry] =
+ new Iterator[ZipEntry] {
+ var nextEntry = Option.empty[ZipEntry]
+ def update() =
+ nextEntry = Option(zipStream.getNextEntry)
+
+ update()
+
+ def hasNext = nextEntry.nonEmpty
+ def next() = {
+ val ent = nextEntry.get
+ update()
+ ent
+ }
+ }
+
+ def jarClassNames(jar: File): Seq[String] = {
+
+ var fis: FileInputStream = null
+ var zis: JarInputStream = null
+
+ try {
+ fis = new FileInputStream(jar)
+ zis = new JarInputStream(fis)
+
+ zipEntries(zis)
+ .map(_.getName)
+ .filter(_.endsWith(".class"))
+ .map(_.stripSuffix(".class").replace('/', '.'))
+ .toVector
+ } finally {
+ if (zis != null)
+ zis.close()
+ if (fis != null)
+ fis.close()
+ }
+ }
+
+ def createPackage(
+ baseJar: File,
+ currentProject: Project,
+ res: Resolution,
+ configs: Map[String, Set[String]],
+ artifactFilesOrErrors: Map[Artifact, FileError \/ File],
+ shadingNamespace: String,
+ baseConfig: String,
+ shadedConf: String,
+ log: sbt.Logger
+ ) = {
+
+ val outputJar = new File(
+ baseJar.getParentFile,
+ baseJar.getName.stripSuffix(".jar") + "-shading.jar"
+ )
+
+ def configDependencies(config: String) = {
+
+ def minDependencies(dependencies: Set[Dependency]): Set[Dependency] =
+ Orders.minDependencies(
+ dependencies,
+ dep =>
+ res
+ .projectCache
+ .get(dep)
+ .map(_._2.configurations)
+ .getOrElse(Map.empty)
+ )
+
+ val includedConfigs = configs.getOrElse(config, Set.empty) + config
+
+ minDependencies(
+ currentProject
+ .dependencies
+ .collect {
+ case (cfg, dep) if includedConfigs(cfg) =>
+ dep
+ }
+ .toSet
+ )
+ }
+
+ val dependencyArtifacts = res.dependencyArtifacts.toMap
+
+ val artifactFilesOrErrors0 = artifactFilesOrErrors
+ .collect {
+ case (a, \/-(f)) => a.url -> f
+ }
+
+ val compileDeps = configDependencies(baseConfig)
+ val shadedDeps = configDependencies(shadedConf)
+
+ val compileOnlyDeps = compileDeps.filterNot(shadedDeps)
+
+ log.info(s"Found ${compileDeps.size} dependencies in $baseConfig")
+ log.debug(compileDeps.toVector.map(" " + _).sorted.mkString("\n"))
+ log.info(s"Found ${compileOnlyDeps.size} dependencies only in $baseConfig")
+ log.debug(compileOnlyDeps.toVector.map(" " + _).sorted.mkString("\n"))
+ log.info(s"Found ${shadedDeps.size} dependencies in $shadedConf")
+ log.debug(shadedDeps.toVector.map(" " + _).sorted.mkString("\n"))
+
+ def files(deps: Set[Dependency]) = res
+ .subset(deps)
+ .dependencies
+ .toSeq
+ .flatMap(dependencyArtifacts.get)
+ .map(_.url)
+ .flatMap(artifactFilesOrErrors0.get)
+
+ val compileOnlyJars = files(compileOnlyDeps)
+ val shadedJars = files(shadedDeps)
+
+ log.info(s"Found ${compileOnlyJars.length} JAR(s) only in $baseConfig")
+ log.debug(compileOnlyJars.map(" " + _).sorted.mkString("\n"))
+ log.info(s"Found ${shadedJars.length} JAR(s) in $shadedConf")
+ log.debug(shadedJars.map(" " + _).sorted.mkString("\n"))
+
+ val shadeJars = shadedJars.filterNot(compileOnlyJars.toSet)
+ val shadeClasses = shadeJars.flatMap(Shading.jarClassNames)
+
+ log.info(s"Will shade ${shadeClasses.length} class(es)")
+ log.debug(shadeClasses.map(" " + _).sorted.mkString("\n"))
+
+ val processor = new DefaultJarProcessor
+ for (cls <- shadeClasses)
+ processor.addClassRename(new ClassRename(cls, shadingNamespace + ".@0"))
+
+ val transformer = new JarTransformer(outputJar, processor)
+ val cp = new ClassPath(file(sys.props("user.dir")), (baseJar +: shadeJars).toArray)
+ transformer.transform(cp)
+
+ outputJar
+ }
+
+}
\ No newline at end of file
diff --git a/sbt-shading/src/main/scala-2.10/coursier/ShadingPlugin.scala b/sbt-shading/src/main/scala-2.10/coursier/ShadingPlugin.scala
new file mode 100644
index 000000000..9b262a61a
--- /dev/null
+++ b/sbt-shading/src/main/scala-2.10/coursier/ShadingPlugin.scala
@@ -0,0 +1,97 @@
+package coursier
+
+import coursier.ivy.IvyXml.{ mappings => ivyXmlMappings }
+import sbt.Keys._
+import sbt.{AutoPlugin, Compile, Configuration, TaskKey, inConfig}
+
+object ShadingPlugin extends AutoPlugin {
+
+ override def trigger = noTrigger
+
+ override def requires = sbt.plugins.IvyPlugin
+
+ private val baseSbtConfiguration = Compile
+ val Shading = Configuration("shading", "", isPublic = false, List(baseSbtConfiguration), transitive = true)
+
+ private val baseDependencyConfiguration = "compile"
+ val Shaded = Configuration("shaded", "", isPublic = true, List(), transitive = true)
+
+ val shadingNamespace = TaskKey[String]("shading-namespace")
+
+ object autoImport {
+
+ /** Scope for shading related tasks */
+ val Shading = ShadingPlugin.Shading
+
+ /** Ivy configuration for shaded dependencies */
+ val Shaded = ShadingPlugin.Shaded
+
+ val shadingNamespace = ShadingPlugin.shadingNamespace
+ }
+
+ // same as similar things under sbt.Classpaths, tweaking a bit the configuration scope
+ lazy val shadingDefaultArtifactTasks =
+ makePom +: Seq(packageBin, packageSrc, packageDoc).map(_.in(Shading))
+ lazy val shadingJvmPublishSettings = Seq(
+ artifacts <<= sbt.Classpaths.artifactDefs(shadingDefaultArtifactTasks),
+ packagedArtifacts <<= sbt.Classpaths.packaged(shadingDefaultArtifactTasks)
+ )
+
+ import CoursierPlugin.autoImport._
+
+ override lazy val projectSettings =
+ Seq(
+ coursierConfigurations <<= Tasks.coursierConfigurationsTask(
+ Some(baseDependencyConfiguration -> Shaded.name)
+ ),
+ ivyConfigurations := Shaded +: ivyConfigurations.value.map {
+ conf =>
+ if (conf.name == "compile")
+ conf.extend(Shaded)
+ else
+ conf
+ }
+ ) ++
+ inConfig(Shading)(
+ sbt.Defaults.configSettings ++
+ sbt.Classpaths.ivyBaseSettings ++
+ sbt.Classpaths.ivyPublishSettings ++
+ shadingJvmPublishSettings ++
+ CoursierPlugin.coursierSettings(
+ Some(baseDependencyConfiguration -> Shaded.name),
+ Seq(Shading -> Compile.name)
+ ) ++
+ CoursierPlugin.treeSettings ++
+ Seq(
+ configuration := baseSbtConfiguration, // wuw
+ ivyConfigurations := ivyConfigurations.in(baseSbtConfiguration).value
+ .filter(_.name != Shaded.name)
+ .map(c => c.copy(extendsConfigs = c.extendsConfigs.filter(_.name != Shaded.name))),
+ libraryDependencies := libraryDependencies.in(baseSbtConfiguration).value.filter { dep =>
+ val isShaded = dep.configurations.exists { mappings =>
+ ivyXmlMappings(mappings).exists(_._1 == Shaded.name)
+ }
+
+ !isShaded
+ },
+ // required for cross-projects in particular
+ unmanagedSourceDirectories := (unmanagedSourceDirectories in Compile).value,
+ packageBin := {
+ coursier.Shading.createPackage(
+ packageBin.in(baseSbtConfiguration).value,
+ coursierProject.in(baseSbtConfiguration).value,
+ coursierResolution.in(baseSbtConfiguration).value,
+ coursierConfigurations.in(baseSbtConfiguration).value,
+ Keys.coursierArtifacts.in(baseSbtConfiguration).value,
+ shadingNamespace.?.value.getOrElse {
+ throw new NoSuchElementException("shadingNamespace key not set")
+ },
+ baseDependencyConfiguration,
+ Shaded.name,
+ streams.value.log
+ )
+ }
+ )
+ )
+
+}
\ No newline at end of file
diff --git a/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/build.sbt b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/build.sbt
new file mode 100644
index 000000000..0144a1ce2
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/build.sbt
@@ -0,0 +1,20 @@
+
+lazy val root = crossProject
+ .in(file("."))
+ .jvmConfigure(
+ _.enablePlugins(coursier.ShadingPlugin)
+ )
+ .jvmSettings(
+ shadingNamespace := "test.shaded",
+ libraryDependencies += "io.argonaut" %% "argonaut" % "6.2-RC2" % "shaded"
+ )
+ .settings(
+ scalaVersion := "2.11.8",
+ organization := "io.get-coursier.test",
+ name := "shading-cross-test",
+ version := "0.1.0-SNAPSHOT",
+ libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value
+ )
+
+lazy val jvm = root.jvm
+lazy val js = root.js
diff --git a/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/coursier b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/coursier
new file mode 100755
index 000000000..13c8a2b55
Binary files /dev/null and b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/coursier differ
diff --git a/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/jvm/src/main/scala/Main.scala b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/jvm/src/main/scala/Main.scala
new file mode 100644
index 000000000..30502dda1
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/jvm/src/main/scala/Main.scala
@@ -0,0 +1,21 @@
+import java.io.File
+import java.nio.file.Files
+
+import argonaut._
+
+import Foo._
+
+object Main extends App {
+
+ val expectedClassName0 = expectedClassName(args.headOption == Some("--shaded"))
+
+ Console.err.println(s"Expected class name: $expectedClassName0")
+ Console.err.println(s"Class name: $className")
+
+ if (className != expectedClassName0)
+ sys.error(s"Expected class name $expectedClassName0, got $className")
+
+ val msg = Json.obj().nospaces
+
+ Files.write(new File("output").toPath, msg.getBytes("UTF-8"))
+}
diff --git a/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/project/plugins.sbt b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/project/plugins.sbt
new file mode 100644
index 000000000..fc3a48bf6
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/project/plugins.sbt
@@ -0,0 +1,33 @@
+{
+ 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-shading" % pluginVersion)
+}
+
+// for the locally publish jarjar
+resolvers += Resolver.mavenLocal
+
+val coursierJarjarVersion = "1.0.1-coursier-SNAPSHOT"
+
+def coursierJarjarFoundInM2 =
+ (file(sys.props("user.home")) / s".m2/repository/org/anarres/jarjar/jarjar-core/$coursierJarjarVersion").exists()
+
+def jarjarVersion =
+ if (coursierJarjarFoundInM2)
+ coursierJarjarVersion
+ else
+ sys.error(
+ "Ad hoc jarjar version not found. Run\n" +
+ " git clone https://github.com/alexarchambault/jarjar.git && cd jarjar && git checkout 249c8dbb970f8 && ./gradlew install\n" +
+ "to run this test"
+ )
+
+libraryDependencies += "org.anarres.jarjar" % "jarjar-core" % jarjarVersion
+
+addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.13")
diff --git a/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/shared/src/main/scala/Foo.scala b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/shared/src/main/scala/Foo.scala
new file mode 100644
index 000000000..6e510b152
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/shared/src/main/scala/Foo.scala
@@ -0,0 +1,16 @@
+
+import argonaut._
+
+object Foo {
+
+ def expectedClassName(shaded: Boolean) =
+ if (shaded)
+ "test.shaded.argonaut.Json"
+ else
+ // Don't use the literal "argonaut.Json", that seems to get
+ // changed to "test.shaded.argonaut.Json" by shading
+ "argonaut" + '.' + "Json"
+
+ val className = classOf[Json].getName
+
+}
diff --git a/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/test b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/test
new file mode 100644
index 000000000..72419bd1d
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/cross-project-shading/test
@@ -0,0 +1,10 @@
+$ delete output
+> rootJVM/run
+$ exists output
+$ delete output
+> rootJVM/publishLocal
+$ exec java -jar coursier launch io.get-coursier.test:shading-cross-test_2.11:0.1.0-SNAPSHOT
+-$ exec java -jar coursier launch io.get-coursier.test:shading-cross-test_2.11:0.1.0-SNAPSHOT -- --shaded
+> rootJVM/shading:publishLocal
+-$ exec java -jar coursier launch io.get-coursier.test:shading-cross-test_2.11:0.1.0-SNAPSHOT
+$ exec java -jar coursier launch io.get-coursier.test:shading-cross-test_2.11:0.1.0-SNAPSHOT -- --shaded
diff --git a/sbt-shading/src/sbt-test/sbt-shading/shading/build.sbt b/sbt-shading/src/sbt-test/sbt-shading/shading/build.sbt
new file mode 100644
index 000000000..c125c822d
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/shading/build.sbt
@@ -0,0 +1,10 @@
+
+enablePlugins(coursier.ShadingPlugin)
+shadingNamespace := "test.shaded"
+
+libraryDependencies += "io.argonaut" %% "argonaut" % "6.2-RC2" % "shaded"
+
+scalaVersion := "2.11.8"
+organization := "io.get-coursier.test"
+name := "shading-base-test"
+version := "0.1.0-SNAPSHOT"
diff --git a/sbt-shading/src/sbt-test/sbt-shading/shading/coursier b/sbt-shading/src/sbt-test/sbt-shading/shading/coursier
new file mode 100755
index 000000000..13c8a2b55
Binary files /dev/null and b/sbt-shading/src/sbt-test/sbt-shading/shading/coursier differ
diff --git a/sbt-shading/src/sbt-test/sbt-shading/shading/project/plugins.sbt b/sbt-shading/src/sbt-test/sbt-shading/shading/project/plugins.sbt
new file mode 100644
index 000000000..8f83e814d
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/shading/project/plugins.sbt
@@ -0,0 +1,31 @@
+{
+ 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-shading" % pluginVersion)
+}
+
+// for the locally publish jarjar
+resolvers += Resolver.mavenLocal
+
+val coursierJarjarVersion = "1.0.1-coursier-SNAPSHOT"
+
+def coursierJarjarFoundInM2 =
+ (file(sys.props("user.home")) / s".m2/repository/org/anarres/jarjar/jarjar-core/$coursierJarjarVersion").exists()
+
+def jarjarVersion =
+ if (coursierJarjarFoundInM2)
+ coursierJarjarVersion
+ else
+ sys.error(
+ "Ad hoc jarjar version not found. Run\n" +
+ " git clone https://github.com/alexarchambault/jarjar.git && cd jarjar && git checkout 249c8dbb970f8 && ./gradlew install\n" +
+ "to run this test"
+ )
+
+libraryDependencies += "org.anarres.jarjar" % "jarjar-core" % jarjarVersion
diff --git a/sbt-shading/src/sbt-test/sbt-shading/shading/src/main/scala/Main.scala b/sbt-shading/src/sbt-test/sbt-shading/shading/src/main/scala/Main.scala
new file mode 100644
index 000000000..b7eee31a8
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/shading/src/main/scala/Main.scala
@@ -0,0 +1,27 @@
+import java.io.File
+import java.nio.file.Files
+
+import argonaut._
+
+object Main extends App {
+
+ val expectedClassName =
+ if (args.headOption == Some("--shaded"))
+ "test.shaded.argonaut.Json"
+ else
+ // Don't use the literal "argonaut.Json", that seems to get
+ // changed to "test.shaded.argonaut.Json" by shading
+ "argonaut" + '.' + "Json"
+
+ val className = classOf[Json].getName
+
+ Console.err.println(s"Expected class name: $expectedClassName")
+ Console.err.println(s"Class name: $className")
+
+ if (className != expectedClassName)
+ sys.error(s"Expected class name $expectedClassName, got $className")
+
+ val msg = Json.obj().nospaces
+
+ Files.write(new File("output").toPath, msg.getBytes("UTF-8"))
+}
diff --git a/sbt-shading/src/sbt-test/sbt-shading/shading/test b/sbt-shading/src/sbt-test/sbt-shading/shading/test
new file mode 100644
index 000000000..6f020327e
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/shading/test
@@ -0,0 +1,9 @@
+$ delete output
+> run
+$ exists output
+> publishLocal
+$ exec java -jar coursier launch io.get-coursier.test:shading-base-test_2.11:0.1.0-SNAPSHOT
+-$ exec java -jar coursier launch io.get-coursier.test:shading-base-test_2.11:0.1.0-SNAPSHOT -- --shaded
+> shading:publishLocal
+-$ exec java -jar coursier launch io.get-coursier.test:shading-base-test_2.11:0.1.0-SNAPSHOT
+$ exec java -jar coursier launch io.get-coursier.test:shading-base-test_2.11:0.1.0-SNAPSHOT -- --shaded
diff --git a/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/build.sbt b/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/build.sbt
new file mode 100644
index 000000000..3f4280d74
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/build.sbt
@@ -0,0 +1,14 @@
+
+enablePlugins(coursier.ShadingPlugin)
+shadingNamespace := "test.shaded"
+
+libraryDependencies ++= Seq(
+ "com.github.alexarchambault" %% "argonaut-shapeless_6.2" % "1.2.0-M4" % "shaded",
+ "com.chuusai" %% "shapeless" % "2.3.2",
+ "org.scala-lang" % "scala-reflect" % scalaVersion.value
+)
+
+scalaVersion := "2.11.8"
+organization := "io.get-coursier.test"
+name := "shading-transitive-test"
+version := "0.1.0-SNAPSHOT"
diff --git a/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/coursier b/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/coursier
new file mode 100755
index 000000000..13c8a2b55
Binary files /dev/null and b/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/coursier differ
diff --git a/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/project/plugins.sbt b/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/project/plugins.sbt
new file mode 100644
index 000000000..8f83e814d
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/project/plugins.sbt
@@ -0,0 +1,31 @@
+{
+ 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-shading" % pluginVersion)
+}
+
+// for the locally publish jarjar
+resolvers += Resolver.mavenLocal
+
+val coursierJarjarVersion = "1.0.1-coursier-SNAPSHOT"
+
+def coursierJarjarFoundInM2 =
+ (file(sys.props("user.home")) / s".m2/repository/org/anarres/jarjar/jarjar-core/$coursierJarjarVersion").exists()
+
+def jarjarVersion =
+ if (coursierJarjarFoundInM2)
+ coursierJarjarVersion
+ else
+ sys.error(
+ "Ad hoc jarjar version not found. Run\n" +
+ " git clone https://github.com/alexarchambault/jarjar.git && cd jarjar && git checkout 249c8dbb970f8 && ./gradlew install\n" +
+ "to run this test"
+ )
+
+libraryDependencies += "org.anarres.jarjar" % "jarjar-core" % jarjarVersion
diff --git a/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/src/main/scala/Main.scala b/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/src/main/scala/Main.scala
new file mode 100644
index 000000000..b7eee31a8
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/src/main/scala/Main.scala
@@ -0,0 +1,27 @@
+import java.io.File
+import java.nio.file.Files
+
+import argonaut._
+
+object Main extends App {
+
+ val expectedClassName =
+ if (args.headOption == Some("--shaded"))
+ "test.shaded.argonaut.Json"
+ else
+ // Don't use the literal "argonaut.Json", that seems to get
+ // changed to "test.shaded.argonaut.Json" by shading
+ "argonaut" + '.' + "Json"
+
+ val className = classOf[Json].getName
+
+ Console.err.println(s"Expected class name: $expectedClassName")
+ Console.err.println(s"Class name: $className")
+
+ if (className != expectedClassName)
+ sys.error(s"Expected class name $expectedClassName, got $className")
+
+ val msg = Json.obj().nospaces
+
+ Files.write(new File("output").toPath, msg.getBytes("UTF-8"))
+}
diff --git a/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/test b/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/test
new file mode 100644
index 000000000..84b72a875
--- /dev/null
+++ b/sbt-shading/src/sbt-test/sbt-shading/transitive-shading/test
@@ -0,0 +1,9 @@
+$ delete output
+> run
+$ exists output
+> publishLocal
+$ exec java -jar coursier launch io.get-coursier.test:shading-transitive-test_2.11:0.1.0-SNAPSHOT
+-$ exec java -jar coursier launch io.get-coursier.test:shading-transitive-test_2.11:0.1.0-SNAPSHOT -- --shaded
+> shading:publishLocal
+-$ exec java -jar coursier launch io.get-coursier.test:shading-transitive-test_2.11:0.1.0-SNAPSHOT
+$ exec java -jar coursier launch io.get-coursier.test:shading-transitive-test_2.11:0.1.0-SNAPSHOT -- --shaded
diff --git a/tests/shared/src/test/resources/resolutions/io.get-coursier/coursier_2.11/1.0.0-SNAPSHOT b/tests/shared/src/test/resources/resolutions/io.get-coursier/coursier_2.11/1.0.0-SNAPSHOT
index cd8ddc0fb..a5ddf5449 100644
--- a/tests/shared/src/test/resources/resolutions/io.get-coursier/coursier_2.11/1.0.0-SNAPSHOT
+++ b/tests/shared/src/test/resources/resolutions/io.get-coursier/coursier_2.11/1.0.0-SNAPSHOT
@@ -2,7 +2,7 @@ com.lihaoyi:fastparse-utils_2.11:0.4.2:default
com.lihaoyi:fastparse_2.11:0.4.2:default
com.lihaoyi:sourcecode_2.11:0.1.3:default
io.get-coursier:coursier_2.11:1.0.0-SNAPSHOT:compile
-org.jsoup:jsoup:1.9.2:default
+org.jsoup:jsoup:1.10.2:default
org.scala-lang:scala-library:2.11.8:default
-org.scala-lang.modules:scala-xml_2.11:1.0.5:default
-org.scalaz:scalaz-core_2.11:7.2.7:default
+org.scala-lang.modules:scala-xml_2.11:1.0.6:default
+org.scalaz:scalaz-core_2.11:7.2.8:default