diff --git a/cache/jvm/src/main/scala/coursier/Cache.scala b/cache/jvm/src/main/scala/coursier/Cache.scala index 005718682..ffa68312a 100644 --- a/cache/jvm/src/main/scala/coursier/Cache.scala +++ b/cache/jvm/src/main/scala/coursier/Cache.scala @@ -9,7 +9,6 @@ import java.util.regex.Pattern import coursier.core.Authentication import coursier.ivy.IvyRepository -import coursier.internal.FileUtil import scala.annotation.tailrec import java.io.{Serializable => _, _} @@ -689,7 +688,7 @@ object Cache { S.schedule[Either[FileError, Unit]](pool) { if (referenceFileExists) { if (!errFile0.exists()) - FileUtil.write(errFile0, "".getBytes(UTF_8)) + Files.write(errFile0.toPath, Array.emptyByteArray) } Right(()) @@ -891,7 +890,7 @@ object Cache { val sumFile = localFile(sumUrl, cache, artifact.authentication.map(_.user)) S.schedule(pool) { - val sumOpt = parseRawChecksum(FileUtil.readAllBytes(sumFile)) + val sumOpt = parseRawChecksum(Files.readAllBytes(sumFile.toPath)) sumOpt match { case None => @@ -1038,7 +1037,7 @@ object Cache { def notFound(f: File) = Left(s"${f.getCanonicalPath} not found") def read(f: File) = - try Right(new String(FileUtil.readAllBytes(f), UTF_8)) + try Right(new String(Files.readAllBytes(f.toPath), UTF_8)) catch { case NonFatal(e) => Left(s"Could not read (file:${f.getCanonicalPath}): ${e.getMessage}") diff --git a/cache/jvm/src/main/scala/coursier/internal/FileUtil.scala b/cache/jvm/src/main/scala/coursier/internal/FileUtil.scala index 1ad5f4d1f..5d4bdf511 100644 --- a/cache/jvm/src/main/scala/coursier/internal/FileUtil.scala +++ b/cache/jvm/src/main/scala/coursier/internal/FileUtil.scala @@ -1,21 +1,12 @@ package coursier.internal -import java.io.{ByteArrayOutputStream, File, FileInputStream, FileOutputStream, InputStream} -import java.nio.file.Files +import java.io.{ByteArrayOutputStream, InputStream} object FileUtil { - def write(file: File, bytes: Array[Byte]): Unit = { - var fos: FileOutputStream = null - try { - fos = new FileOutputStream(file) - fos.write(bytes) - fos.close() - } finally { - if (fos != null) fos.close() - } - } - + // Won't be necessary anymore with Java 9 + // (https://docs.oracle.com/javase/9/docs/api/java/io/InputStream.html#readAllBytes--, + // via https://stackoverflow.com/questions/1264709/convert-inputstream-to-byte-array-in-java/37681322#37681322) def readFully(is: InputStream): Array[Byte] = { val buffer = new ByteArrayOutputStream val data = Array.ofDim[Byte](16384) @@ -31,18 +22,4 @@ object FileUtil { buffer.toByteArray } - def readAllBytes(file: File): Array[Byte] = { - var fis: FileInputStream = null - try { - fis = new FileInputStream(file) - readFully(fis) - } finally { - if (fis != null) - fis.close() - } - } - - def createTempDirectory(prefix: String): File = - Files.createTempDirectory(prefix).toFile - } \ No newline at end of file diff --git a/cli/src/main/scala-2.12/coursier/cli/Bootstrap.scala b/cli/src/main/scala-2.12/coursier/cli/Bootstrap.scala index 5124467f7..a5eba41f5 100644 --- a/cli/src/main/scala-2.12/coursier/cli/Bootstrap.scala +++ b/cli/src/main/scala-2.12/coursier/cli/Bootstrap.scala @@ -203,7 +203,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 Files.write(output0.toPath, 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) diff --git a/cli/src/main/scala-2.12/coursier/cli/SparkOutputHelper.scala b/cli/src/main/scala-2.12/coursier/cli/SparkOutputHelper.scala index 3bfa043a2..32c418996 100644 --- a/cli/src/main/scala-2.12/coursier/cli/SparkOutputHelper.scala +++ b/cli/src/main/scala-2.12/coursier/cli/SparkOutputHelper.scala @@ -2,8 +2,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 +import java.nio.file.Files import scala.util.control.NonFatal @@ -56,7 +55,7 @@ object SparkOutputHelper { if (!written) { println(s"Detected YARN app ID $id") Option(yarnAppFile.getParentFile).foreach(_.mkdirs()) - FileUtil.write(yarnAppFile, id.getBytes(UTF_8)) + Files.write(yarnAppFile.toPath, id.getBytes(UTF_8)) written = true } } diff --git a/cli/src/main/scala-2.12/coursier/cli/spark/Assembly.scala b/cli/src/main/scala-2.12/coursier/cli/spark/Assembly.scala index ed2c01ad5..d94d9ff18 100644 --- a/cli/src/main/scala-2.12/coursier/cli/spark/Assembly.scala +++ b/cli/src/main/scala-2.12/coursier/cli/spark/Assembly.scala @@ -13,7 +13,6 @@ import coursier.Cache import coursier.cli.Helper import coursier.cli.options.CommonOptions import coursier.cli.util.Zip -import coursier.internal.FileUtil import scala.collection.mutable @@ -225,7 +224,7 @@ object Assembly { throw new Exception(s"SHA-1 file not found for ${a.url}") } - val sumOpt = Cache.parseRawChecksum(FileUtil.readAllBytes(f)) + val sumOpt = Cache.parseRawChecksum(Files.readAllBytes(f.toPath)) sumOpt match { case Some(sum) => diff --git a/cli/src/test/scala-2.12/coursier/cli/CliFetchIntegrationTest.scala b/cli/src/test/scala-2.12/coursier/cli/CliFetchIntegrationTest.scala index 1b6efd1d2..9bba0e78d 100644 --- a/cli/src/test/scala-2.12/coursier/cli/CliFetchIntegrationTest.scala +++ b/cli/src/test/scala-2.12/coursier/cli/CliFetchIntegrationTest.scala @@ -7,10 +7,11 @@ import argonaut.Argonaut._ import caseapp.core.RemainingArgs import coursier.cli.options._ import coursier.cli.util.{DepNode, ReportNode} -import coursier.internal.FileUtil import java.io._ import java.net.URLEncoder.encode import java.nio.charset.StandardCharsets.UTF_8 +import java.nio.file.{Files, Paths} + import org.junit.runner.RunWith import org.scalatest.FlatSpec import org.scalatest.junit.JUnitRunner @@ -816,81 +817,79 @@ class CliFetchIntegrationTest extends FlatSpec with CliTestLib { "Bad pom resolve" should "succeed with retry" in withTempDir("tmp_dir") { dir => { - def runFetchJunit = { + def runFetchJunit() = { val fetchOpt = FetchOptions(common = CommonOptions(cacheOptions = CacheOptions(cache = dir.getAbsolutePath))) val fetch = Fetch(fetchOpt, RemainingArgs(Seq("junit:junit:4.12"), Seq())) assert(fetch.files0.map(_.getName).toSet .equals(Set("junit-4.12.jar", "hamcrest-core-1.3.jar"))) val junitJarPath = fetch.files0.map(_.getAbsolutePath()).filter(_.contains("junit-4.12.jar")) .head - val junitPomFile = new File(junitJarPath.replace(".jar", ".pom")) - val junitPomShaFile = new File(junitJarPath.replace(".jar", ".pom.sha1")) - assert(junitPomFile.exists()) - assert(junitPomShaFile.exists()) + val junitPomFile = Paths.get(junitJarPath.replace(".jar", ".pom")) + val junitPomShaFile = Paths.get(junitJarPath.replace(".jar", ".pom.sha1")) + assert(Files.isRegularFile(junitPomFile)) + assert(Files.isRegularFile(junitPomShaFile)) junitPomFile } - val junitPomFile: File = runFetchJunit - val originalPomContent = FileUtil.readAllBytes(junitPomFile) + val junitPomFile = runFetchJunit() + val originalPomContent = Files.readAllBytes(junitPomFile) // Corrupt the pom content - FileUtil.write(junitPomFile, "bad pom".getBytes(UTF_8)) + Files.write(junitPomFile, "bad pom".getBytes(UTF_8)) // Run fetch again and it should pass because of retrying om the bad pom. - val pom = runFetchJunit - assert(FileUtil.readAllBytes(pom).sameElements(originalPomContent)) + val pom = runFetchJunit() + assert(Files.readAllBytes(pom).sameElements(originalPomContent)) } } "Bad jar resolve" should "succeed with retry" in withTempDir("tmp_dir") { dir => { - def runFetchJunit = { + def runFetchJunit() = { val fetchOpt = FetchOptions(common = CommonOptions(cacheOptions = CacheOptions(cache = dir.getAbsolutePath))) val fetch = Fetch(fetchOpt, RemainingArgs(Seq("junit:junit:4.12"), Seq())) assert(fetch.files0.map(_.getName).toSet .equals(Set("junit-4.12.jar", "hamcrest-core-1.3.jar"))) val junitJarPath = fetch.files0.map(_.getAbsolutePath()).filter(_.contains("junit-4.12.jar")) .head - val junitJarFile = new File(junitJarPath) - junitJarFile + Paths.get(junitJarPath) } - val originalJunitJar: File = runFetchJunit - val originalJunitJarContent = FileUtil.readAllBytes(originalJunitJar) + val originalJunitJar = runFetchJunit() + val originalJunitJarContent = Files.readAllBytes(originalJunitJar) // Corrupt the jar content - FileUtil.write(originalJunitJar, "bad jar".getBytes(UTF_8)) + Files.write(originalJunitJar, "bad jar".getBytes(UTF_8)) // Run fetch again and it should pass because of retrying on the bad jar. - val jar = runFetchJunit - assert(FileUtil.readAllBytes(jar).sameElements(originalJunitJarContent)) + val jar = runFetchJunit() + assert(Files.readAllBytes(jar).sameElements(originalJunitJarContent)) } } "Wrong range partial artifact resolve" should "succeed with retry" in withTempDir("tmp_dir") { dir => { - def runFetchJunit = { + def runFetchJunit() = { val fetchOpt = FetchOptions(common = CommonOptions(mode = "force", cacheOptions = CacheOptions(cache = dir.getAbsolutePath))) val fetch = Fetch(fetchOpt, RemainingArgs(Seq("junit:junit:4.6"), Seq())) assert(fetch.files0.map(_.getName).toSet .equals(Set("junit-4.6.jar"))) val junitJarPath = fetch.files0.map(_.getAbsolutePath()).filter(_.contains("junit-4.6.jar")) .head - val junitJarFile = new File(junitJarPath) - junitJarFile + Paths.get(junitJarPath) } - val originalJunitJar: File = runFetchJunit + val originalJunitJar = runFetchJunit() - val originalJunitJarContent = FileUtil.readAllBytes(originalJunitJar) + val originalJunitJarContent = Files.readAllBytes(originalJunitJar) // Move the jar to partial (but complete) download - val newJunitJar: File = new File(originalJunitJar.getAbsolutePath + ".part") - originalJunitJar.renameTo(newJunitJar) + val newJunitJar = originalJunitJar.getParent.resolve(originalJunitJar.getFileName.toString + ".part") + Files.move(originalJunitJar, newJunitJar) // Run fetch again and it should pass because of retrying on the partial jar. - val jar = runFetchJunit - assert(FileUtil.readAllBytes(jar).sameElements(originalJunitJarContent)) + val jar = runFetchJunit() + assert(Files.readAllBytes(jar).sameElements(originalJunitJarContent)) } } } diff --git a/cli/src/test/scala-2.12/coursier/cli/CliTestLib.scala b/cli/src/test/scala-2.12/coursier/cli/CliTestLib.scala index cb8b2852f..7502bfc9c 100644 --- a/cli/src/test/scala-2.12/coursier/cli/CliTestLib.scala +++ b/cli/src/test/scala-2.12/coursier/cli/CliTestLib.scala @@ -1,7 +1,7 @@ package coursier.cli -import coursier.internal.FileUtil import java.io.{File, FileWriter} +import java.nio.file.Files trait CliTestLib { @@ -24,7 +24,7 @@ trait CliTestLib { def withTempDir( prefix: String )(testCode: File => Any) { - val dir = FileUtil.createTempDirectory(prefix) // create the fixture + val dir = Files.createTempDirectory(prefix).toFile // create the fixture try { testCode(dir) // "loan" the fixture to the test } finally { diff --git a/project/Mima.scala b/project/Mima.scala index 4cdd2c162..e2230a066 100644 --- a/project/Mima.scala +++ b/project/Mima.scala @@ -10,7 +10,6 @@ object Mima { // Important: the line with the "binary compatibility versions" comment below is matched during releases def binaryCompatibilityVersions = Set( - "1.1.0-M1", "" // binary compatibility versions ) diff --git a/project/Release.scala b/project/Release.scala index e245b7574..fe847ea7c 100644 --- a/project/Release.scala +++ b/project/Release.scala @@ -244,6 +244,8 @@ object Release { val mimaVersionsPattern = s"(?m)^(\\s+)${Pattern.quote("\"\" // binary compatibility versions")}$$".r + val milestonePattern = ("[^-]+" + Pattern.quote("-M") + "[0-9]+(-[0-9]+)*").r + val updateMimaVersions = ReleaseStep { state => val vcs = state.vcs @@ -253,28 +255,33 @@ object Release { sys.error(s"${ReleaseKeys.versions.label} key not set") } - val baseDir = Project.extract(state).get(baseDirectory.in(ThisBuild)) - val mimaScalaFile = baseDir / "project" / "Mima.scala" + if (milestonePattern.unapplySeq(releaseVer).isEmpty) { - val content = Source.fromFile(mimaScalaFile)(Codec.UTF8).mkString + val baseDir = Project.extract(state).get(baseDirectory.in(ThisBuild)) + val mimaScalaFile = baseDir / "project" / "Mima.scala" - mimaVersionsPattern.findAllIn(content).toVector match { - case Seq() => sys.error(s"Found no matches in $mimaScalaFile") - case Seq(_) => - case _ => sys.error(s"Found too many matches in $mimaScalaFile") - } + val content = Source.fromFile(mimaScalaFile)(Codec.UTF8).mkString - val newContent = mimaVersionsPattern.replaceAllIn( - content, - m => { - val indent = m.group(1) - indent + "\"" + releaseVer + "\",\n" + - indent + "\"\" // binary compatibility versions" + mimaVersionsPattern.findAllIn(content).toVector match { + case Seq() => sys.error(s"Found no matches in $mimaScalaFile") + case Seq(_) => + case _ => sys.error(s"Found too many matches in $mimaScalaFile") } - ) - Files.write(mimaScalaFile.toPath, newContent.getBytes(StandardCharsets.UTF_8)) - vcs.add(mimaScalaFile.getAbsolutePath).!!(log) + val newContent = mimaVersionsPattern.replaceAllIn( + content, + m => { + val indent = m.group(1) + indent + "\"" + releaseVer + "\",\n" + + indent + "\"\" // binary compatibility versions" + } + ) + + Files.write(mimaScalaFile.toPath, newContent.getBytes(StandardCharsets.UTF_8)) + vcs.add(mimaScalaFile.getAbsolutePath).!!(log) + } else + state.log.info(s"$releaseVer is a milestone release, not adding it to the MIMA checks") + state } diff --git a/sbt-coursier/src/main/scala/coursier/IvyXml.scala b/sbt-coursier/src/main/scala/coursier/IvyXml.scala index 3b4f72a03..07a706fdd 100644 --- a/sbt-coursier/src/main/scala/coursier/IvyXml.scala +++ b/sbt-coursier/src/main/scala/coursier/IvyXml.scala @@ -1,13 +1,12 @@ package coursier import java.nio.charset.StandardCharsets.UTF_8 +import java.nio.file.Files -import coursier.internal.FileUtil import org.apache.ivy.core.module.id.ModuleRevisionId import scala.collection.JavaConverters._ import scala.xml.{Node, PrefixedAttribute} - import sbt.internal.librarymanagement.IvySbt object IvyXml { @@ -54,11 +53,11 @@ object IvyXml { val content0 = rawContent(currentProject, shadedConfigOpt) cacheIvyFile.getParentFile.mkdirs() log.info(s"Writing Ivy file $cacheIvyFile") - FileUtil.write(cacheIvyFile, content0.getBytes(UTF_8)) + Files.write(cacheIvyFile.toPath, content0.getBytes(UTF_8)) // Just writing an empty file here... Are these only used? cacheIvyPropertiesFile.getParentFile.mkdirs() - FileUtil.write(cacheIvyPropertiesFile, Array()) + Files.write(cacheIvyPropertiesFile.toPath, Array.emptyByteArray) } def content(project0: Project, shadedConfigOpt: Option[String]): Node = { diff --git a/tests/shared/src/test/scala/coursier/test/CentralTests.scala b/tests/shared/src/test/scala/coursier/test/CentralTests.scala index 497dec1b3..970004948 100644 --- a/tests/shared/src/test/scala/coursier/test/CentralTests.scala +++ b/tests/shared/src/test/scala/coursier/test/CentralTests.scala @@ -54,7 +54,7 @@ abstract class CentralTests extends TestSuite { res } - .future + .future() } def resolutionCheck(