Require Java 8 from now on

This commit is contained in:
Alexandre Archambault 2018-03-12 11:18:19 +01:00
parent 5bd162d5fe
commit dc2e4996f4
15 changed files with 50 additions and 277 deletions

View File

@ -11,6 +11,7 @@ install:
)
[System.IO.Compression.ZipFile]::ExtractToDirectory("C:\sbt-bin.zip", "C:\sbt")
}
- cmd: SET JAVA_HOME=C:\Program Files\Java\jdk1.8.0
- cmd: SET PATH=C:\sbt\sbt\bin;%JAVA_HOME%\bin;%PATH%
- cmd: SET SBT_OPTS=-XX:MaxPermSize=2g -Xmx4g
- git submodule update --init --recursive

View File

@ -10,11 +10,12 @@ import java.util.regex.Pattern
import coursier.core.Authentication
import coursier.ivy.IvyRepository
import coursier.internal.FileUtil
import coursier.util.Base64.Encoder
import scala.annotation.tailrec
import java.io.{Serializable => _, _}
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.{Files, StandardCopyOption}
import java.util.Base64
import coursier.util.{EitherT, Schedulable}
@ -34,9 +35,6 @@ object Cache {
}
}
// java.nio.charset.StandardCharsets.UTF_8 not available in Java 6
private val UTF_8 = Charset.forName("UTF-8")
// Check SHA-1 if available, else be fine with no checksum
val defaultChecksums = Seq(Some("SHA-1"), None)
@ -268,7 +266,9 @@ object Cache {
).r
private def basicAuthenticationEncode(user: String, password: String): String =
(user + ":" + password).getBytes(UTF_8).toBase64
Base64.getEncoder.encodeToString(
s"$user:$password".getBytes(UTF_8)
)
/**
* Returns a `java.net.URL` for `s`, possibly using the custom protocol handlers found under the
@ -334,9 +334,8 @@ object Cache {
var success = false
try {
c.setRequestMethod("HEAD")
val len = Some(c.getContentLength) // TODO Use getContentLengthLong when switching to Java >= 7
.filter(_ >= 0)
.map(_.toLong)
val len = Some(c.getContentLengthLong)
.filter(_ >= 0L)
// TODO 404 Not found could be checked here
@ -581,8 +580,7 @@ object Cache {
else if (responseCode(conn) == Some(401))
Left(FileError.Unauthorized(url, realm = realm(conn)))
else {
// TODO Use the safer getContentLengthLong when switching back to Java >= 7
for (len0 <- Option(conn.getContentLength) if len0 >= 0L) {
for (len0 <- Option(conn.getContentLengthLong) if len0 >= 0L) {
val len = len0 + (if (partialDownload) alreadyDownloaded else 0L)
logger.foreach(_.downloadLength(url, len, alreadyDownloaded, watching = false))
}
@ -601,7 +599,7 @@ object Cache {
withStructureLock(cache) {
file.getParentFile.mkdirs()
FileUtil.atomicMove(tmp, file)
Files.move(tmp.toPath, file.toPath, StandardCopyOption.ATOMIC_MOVE)
}
for (lastModified <- Option(conn.getLastModified) if lastModified > 0L)

View File

@ -1,60 +1,10 @@
package coursier.internal
import java.io._
import java.util.UUID
import java.io.{ByteArrayOutputStream, File, FileInputStream, FileOutputStream, InputStream}
import java.nio.file.Files
/** Java 6-compatible helpers mimicking NIO */
object FileUtil {
private object Java7 {
import java.nio.file.{ Files, StandardCopyOption }
def atomicMove(from: File, to: File): Unit =
Files.move(from.toPath, to.toPath, StandardCopyOption.ATOMIC_MOVE)
def createTempDirectory(prefix: String): File =
Files.createTempDirectory(prefix).toFile
}
private object Java6 {
def move(from: File, to: File): Unit =
if (!from.renameTo(to))
throw new IOException(s"Cannot move $from to $to")
def createTempDirectory(prefix: String): File = {
val tmpBaseDir = new File(sys.props("java.io.tmpdir"))
val tmpDir = new File(tmpBaseDir, s"$prefix-${UUID.randomUUID()}")
tmpDir.mkdirs()
tmpDir
}
}
private def versionGteq(version: String, to: (Int, Int)): Boolean =
version.split('.').take(2).map(s => scala.util.Try(s.toInt).toOption) match {
case Array(Some(major), Some(minor)) =>
Ordering[(Int, Int)].gteq((major, minor), (1, 7))
case _ => false
}
// Fine if set several times (if java7Available() is initially called concurrently)
@volatile private var java7AvailableOpt = Option.empty[Boolean]
private def java7Available(): Boolean =
java7AvailableOpt.getOrElse {
val available = sys.props.get("java.version").exists { version =>
versionGteq(version, (1, 7))
}
java7AvailableOpt = Some(available)
available
}
/** Not guaranteed to be atomic on Java 6 */
def atomicMove(from: File, to: File): Unit =
if (java7Available())
Java7.atomicMove(from, to)
else
Java6.move(from, to)
def write(file: File, bytes: Array[Byte]): Unit = {
var fos: FileOutputStream = null
try {
@ -93,9 +43,6 @@ object FileUtil {
}
def createTempDirectory(prefix: String): File =
if (java7Available())
Java7.createTempDirectory(prefix)
else
Java6.createTempDirectory(prefix)
Files.createTempDirectory(prefix).toFile
}

View File

@ -1,106 +0,0 @@
package coursier.util
import scala.collection.mutable.ArrayBuilder
/**
* Base64 encoder
* @author Mark Lister
* This software is distributed under the 2-Clause BSD license. See the
* LICENSE file in the root of the repository.
*
* Copyright (c) 2014 - 2015 Mark Lister
*
* The repo for this Base64 encoder lives at https://github.com/marklister/base64
* Please send your issues, suggestions and pull requests there.
*/
object Base64 {
final case class B64Scheme(encodeTable: Array[Char], strictPadding: Boolean = true,
postEncode: String => String = identity,
preDecode: String => String = identity) {
lazy val decodeTable = {
val b: Array[Int] = new Array[Int](256)
for (x <- encodeTable.zipWithIndex) {
b(x._1) = x._2.toInt
}
b
}
}
val base64 = new B64Scheme((('A' to 'Z') ++ ('a' to 'z') ++ ('0' to '9') ++ Seq('+', '/')).toArray)
val base64Url = new B64Scheme(base64.encodeTable.dropRight(2) ++ Seq('-', '_'), false,
_.replaceAllLiterally("=", "%3D"),
_.replaceAllLiterally("%3D", "="))
implicit class SeqEncoder(s: Seq[Byte]) {
def toBase64(implicit scheme: B64Scheme = base64): String = Encoder(s.toArray).toBase64
}
implicit class Encoder(b: Array[Byte]) {
val r = new StringBuilder((b.length + 3) * 4 / 3)
lazy val pad = (3 - b.length % 3) % 3
def toBase64(implicit scheme: B64Scheme = base64): String = {
def sixBits(x: Byte, y: Byte, z: Byte): Unit = {
val zz = (x & 0xff) << 16 | (y & 0xff) << 8 | (z & 0xff)
r += scheme.encodeTable(zz >> 18)
r += scheme.encodeTable(zz >> 12 & 0x3f)
r += scheme.encodeTable(zz >> 6 & 0x3f)
r += scheme.encodeTable(zz & 0x3f)
}
for (p <- 0 until b.length - 2 by 3) {
sixBits(b(p), b(p + 1), b(p + 2))
}
pad match {
case 0 =>
case 1 => sixBits(b(b.length - 2), b(b.length - 1), 0)
case 2 => sixBits(b(b.length - 1), 0, 0)
}
r.length = (r.length - pad)
r ++= "=" * pad
scheme.postEncode(r.toString())
}
}
implicit class Decoder(s: String) {
def toByteArray(implicit scheme: B64Scheme = base64): Array[Byte] = {
val pre = scheme.preDecode(s)
val cleanS = pre.replaceAll("=+$", "")
val pad = pre.length - cleanS.length
val computedPad = (4 - (cleanS.length % 4)) % 4
val r = new ArrayBuilder.ofByte
def threeBytes(a: Int, b: Int, c: Int, d: Int): Unit = {
val i = a << 18 | b << 12 | c << 6 | d
r += ((i >> 16).toByte)
r += ((i >> 8).toByte)
r += (i.toByte)
}
if (scheme.strictPadding) {
if (pad > 2) throw new java.lang.IllegalArgumentException("Invalid Base64 String: (excessive padding) " + s)
if (s.length % 4 != 0) throw new java.lang.IllegalArgumentException("Invalid Base64 String: (padding problem) " + s)
}
if (computedPad == 3) throw new java.lang.IllegalArgumentException("Invalid Base64 String: (string length) " + s)
try {
val s = (cleanS + "A" * computedPad)
for (x <- 0 until s.length - 1 by 4) {
val i = scheme.decodeTable(s.charAt(x)) << 18 |
scheme.decodeTable(s.charAt(x + 1)) << 12 |
scheme.decodeTable(s.charAt(x + 2)) << 6 |
scheme.decodeTable(s.charAt(x + 3))
r += ((i >> 16).toByte)
r += ((i >> 8).toByte)
r += (i.toByte)
}
} catch {
case e: NoSuchElementException => throw new java.lang.IllegalArgumentException("Invalid Base64 String: (invalid character)" + e.getMessage + s)
}
val res = r.result
res.slice(0, res.length - computedPad)
}
}
}

View File

@ -2,6 +2,7 @@ package coursier
package cli
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, File, FileInputStream, IOException}
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.Files
import java.nio.file.attribute.PosixFilePermission
import java.util.Properties
@ -156,7 +157,7 @@ object Bootstrap extends CaseApp[BootstrapOptions] {
entry.setTime(time)
outputZip.putNextEntry(entry)
outputZip.write(content.getBytes("UTF-8"))
outputZip.write(content.getBytes(UTF_8))
outputZip.closeEntry()
}
@ -207,7 +208,7 @@ object Bootstrap extends CaseApp[BootstrapOptions] {
"exec java -jar " + options.options.javaOpt.map(s => "'" + s.replace("'", "\\'") + "'").mkString(" ") + " \"$0\" \"$@\""
).mkString("", "\n", "\n")
try FileUtil.write(output0, shellPreamble.getBytes("UTF-8") ++ buffer.toByteArray)
try FileUtil.write(output0, shellPreamble.getBytes(UTF_8) ++ buffer.toByteArray)
catch { case e: IOException =>
Console.err.println(s"Error while writing $output0${Option(e.getMessage).fold("")(" (" + _ + ")")}")
sys.exit(1)

View File

@ -1,6 +1,7 @@
package coursier.cli
import java.io.{BufferedReader, File, InputStream, InputStreamReader, PipedInputStream, PipedOutputStream, PrintStream}
import java.nio.charset.StandardCharsets.UTF_8
import coursier.internal.FileUtil
@ -55,7 +56,7 @@ object SparkOutputHelper {
if (!written) {
println(s"Detected YARN app ID $id")
Option(yarnAppFile.getParentFile).foreach(_.mkdirs())
FileUtil.write(yarnAppFile, id.getBytes("UTF-8"))
FileUtil.write(yarnAppFile, id.getBytes(UTF_8))
written = true
}
}

View File

@ -2,6 +2,8 @@ package coursier.cli.spark
import java.io.{File, FileInputStream, FileOutputStream}
import java.math.BigInteger
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.{Files, StandardCopyOption}
import java.security.MessageDigest
import java.util.jar.{Attributes, JarFile, JarOutputStream, Manifest}
import java.util.regex.Pattern
@ -207,7 +209,7 @@ object Assembly {
extraDependencies: Seq[String],
options: CommonOptions,
artifactTypes: Set[String],
checksumSeed: Array[Byte] = "v1".getBytes("UTF-8")
checksumSeed: Array[Byte] = "v1".getBytes(UTF_8)
): Either[String, (File, Seq[File])] = {
val helper = sparkJarsHelper(scalaVersion, sparkVersion, yarnVersion, default, extraDependencies, options)
@ -240,7 +242,7 @@ object Assembly {
md.update(checksumSeed)
for (c <- checksums.sorted) {
val b = c.getBytes("UTF-8")
val b = c.getBytes(UTF_8)
md.update(b, 0, b.length)
}
@ -271,7 +273,7 @@ object Assembly {
val tmpDest = new File(dest.getParentFile, s".${dest.getName}.part")
// FIXME Acquire lock on tmpDest
Assembly.make(jars, tmpDest, assemblyRules)
FileUtil.atomicMove(tmpDest, dest)
Files.move(tmpDest.toPath, dest.toPath, StandardCopyOption.ATOMIC_MOVE)
Right((dest, jars))
}.left.map(_.describe)
}

View File

@ -1,6 +1,7 @@
package coursier.cli
import java.io._
import java.nio.charset.StandardCharsets.UTF_8
import java.util.zip.ZipInputStream
import caseapp.core.RemainingArgs
@ -69,7 +70,7 @@ class CliBootstrapIntegrationTest extends FlatSpec with CliTestLib {
val zis = new ZipInputStream(new ByteArrayInputStream(actualContent))
val lines = new String(zipEntryContent(zis, "bootstrap-isolation-foo-jar-urls"), "UTF-8").lines.toVector
val lines = new String(zipEntryContent(zis, "bootstrap-isolation-foo-jar-urls"), UTF_8).lines.toVector
val extensions = lines
.map { l =>

View File

@ -31,32 +31,17 @@ object Settings {
scalazBintrayRepository,
sonatypeRepository("releases"),
crossScalaVersions := Seq(scala212, scala211, scala210), // defined for all projects to trump sbt-doge
scalacOptions ++= {
val targetJvm = scalaBinaryVersion.value match {
case "2.10" | "2.11" =>
Seq("-target:jvm-1.6")
case _ =>
Seq()
}
targetJvm ++ Seq(
"-feature",
"-deprecation",
"-language:higherKinds",
"-language:implicitConversions"
)
},
javacOptions ++= {
scalaBinaryVersion.value match {
case "2.10" | "2.11" =>
Seq(
"-source", "1.6",
"-target", "1.6"
)
case _ =>
Seq()
}
},
scalacOptions ++= Seq(
"-target:jvm-1.8",
"-feature",
"-deprecation",
"-language:higherKinds",
"-language:implicitConversions"
),
javacOptions ++= Seq(
"-source", "1.8",
"-target", "1.8"
),
javacOptions.in(Keys.doc) := Seq()
)

View File

@ -1,5 +1,7 @@
package coursier
import java.nio.charset.StandardCharsets.UTF_8
import coursier.internal.FileUtil
import org.apache.ivy.core.module.id.ModuleRevisionId
@ -52,7 +54,7 @@ object IvyXml {
val content0 = rawContent(currentProject, shadedConfigOpt)
cacheIvyFile.getParentFile.mkdirs()
log.info(s"Writing Ivy file $cacheIvyFile")
FileUtil.write(cacheIvyFile, content0.getBytes("UTF-8"))
FileUtil.write(cacheIvyFile, content0.getBytes(UTF_8))
// Just writing an empty file here... Are these only used?
cacheIvyPropertiesFile.getParentFile.mkdirs()

View File

@ -4,9 +4,7 @@ final class ResolutionException(
val error: ResolutionError
) extends Exception(
error.message,
error.cause.orNull
) {
// not using the 4-arg Exception constructor, only available with Java >= 7
setStackTrace(Array()) // don't keep stack trace around (improves readability from the SBT console)
}
error.cause.orNull,
true,
false // don't keep stack trace around (improves readability from the SBT console)
)

View File

@ -134,52 +134,6 @@ checkBinaryCompatibility() {
sbt ++${SCALA_VERSION} coreJVM/mimaReportBinaryIssues cacheJVM/mimaReportBinaryIssues
}
testSbtCoursierJava6() {
sbt ++${SCALA_VERSION} coreJVM/publishLocal cache/publishLocal extra/publishLocal sbt-coursier/publishLocal
git clone https://github.com/alexarchambault/scalacheck-shapeless.git
cd scalacheck-shapeless
git checkout e11ec8b2b069ee598b20ae3f3ad6e00f5edfd7ac
cd project
clean_plugin_sbt
cd project
clean_plugin_sbt
cd ../..
docker run -it --rm \
-v $HOME/.ivy2/local:/root/.ivy2/local \
-v $(pwd):/root/project \
-v $(pwd)/../bin:/root/bin \
-e CI=true \
openjdk:6-jre \
/bin/bash -c "cd /root/project && /root/bin/sbt update"
cd ..
# ensuring resolution error doesn't throw NoSuchMethodError
mkdir -p foo/project
cd foo
echo 'libraryDependencies += "foo" % "bar" % "1.0"' >> build.sbt
echo 'addSbtPlugin("io.get-coursier" % "sbt-coursier" % "'"$VERSION"'")' >> project/plugins.sbt
echo 'sbt.version=0.13.15' >> project/build.properties
docker run -it --rm \
-v $HOME/.ivy2/local:/root/.ivy2/local \
-v $(pwd):/root/project \
-v $(pwd)/../bin:/root/bin \
-e CI=true \
openjdk:6-jre \
/bin/bash -c "cd /root/project && /root/bin/sbt update || true" | tee -a output
grep "coursier.ResolutionException: Encountered 1 error" output
echo "Ok, found ResolutionException in output"
cd ..
}
clean_plugin_sbt() {
mv plugins.sbt plugins.sbt0
grep -v coursier plugins.sbt0 > plugins.sbt || true
echo '
addSbtPlugin("io.get-coursier" % "sbt-coursier" % "'"$VERSION"'")
' >> plugins.sbt
}
publish() {
sbt ++${SCALA_VERSION} publish
}
@ -231,10 +185,6 @@ else
if is210 || is212; then
runSbtCoursierTests
fi
if is210; then
testSbtCoursierJava6
fi
elif sbtShading; then
if is210 || is212; then
runSbtShadingTests
@ -250,10 +200,6 @@ else
validateReadme
checkBinaryCompatibility
fi
# Not using a jdk6 matrix entry with Travis as some sources of coursier require Java 7 to compile
# (even though it won't try to call Java 7 specific methods if it detects it runs under Java 6).
# The tests here check that coursier is nonetheless fine when run under Java 6.
fi

View File

@ -1,7 +1,7 @@
package coursier
import java.io._
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets.UTF_8
import coursier.interop.scalaz._
import coursier.util.EitherT
@ -25,8 +25,6 @@ object Platform {
buffer.toByteArray
}
private lazy val UTF_8 = Charset.forName("UTF-8")
def readFully(is: => InputStream): Task[Either[String, String]] =
Task {
val t = Try {

View File

@ -2,11 +2,10 @@ package coursier
package test
import java.io.File
import java.nio.file.Files
import coursier.cache.protocol.TestprotocolHandler
import coursier.internal.FileUtil
import coursier.interop.scalaz._
import utest._
import scala.util.Try
@ -15,7 +14,7 @@ object CacheFetchTests extends TestSuite {
def check(extraRepo: Repository): Unit = {
val tmpDir = FileUtil.createTempDirectory("coursier-cache-fetch-tests")
val tmpDir = Files.createTempDirectory("coursier-cache-fetch-tests").toFile
def cleanTmpDir() = {
def delete(f: File): Boolean =

View File

@ -1,6 +1,6 @@
package coursier.test
import java.nio.charset.StandardCharsets
import java.nio.charset.StandardCharsets.UTF_8
import java.nio.file.{Files, Paths}
import coursier.interop.scalaz._
@ -24,7 +24,7 @@ package object compatibility {
}
val is = res.openStream()
new String(Platform.readFullySync(is), "UTF-8")
new String(Platform.readFullySync(is), UTF_8)
}
private val baseRepo = {
@ -81,7 +81,7 @@ package object compatibility {
if (fillChunks) {
val path0 = baseResources.resolve(path)
Files.createDirectories(path0.getParent)
Files.write(path0, content.getBytes(StandardCharsets.UTF_8))
Files.write(path0, content.getBytes(UTF_8))
}
}