Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update scrimage to 4.x from 2.x & fix copying resources #529

Merged
merged 7 commits into from
Jan 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ lazy val pluginSettings: Seq[Def.Setting[_]] = Seq(
"com.47deg" %% "github4s" % "0.24.0",
"net.jcazevedo" %% "moultingyaml" % "0.4.2",
"com.lihaoyi" %% "scalatags" % "0.9.3",
"com.sksamuel.scrimage" %% "scrimage-core" % "2.1.8",
"com.sksamuel.scrimage" %% "scrimage-scala" % "4.0.12",
"org.scalatestplus" %% "scalacheck-1-14" % "3.1.4.0" % Test
),
scriptedLaunchOpts ++= Seq(
Expand Down
8 changes: 4 additions & 4 deletions project/dependencies.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ unmanagedResourceDirectories in Compile +=
baseDirectory.in(ThisBuild).value.getParentFile / "src" / "main" / "resources"

libraryDependencies ++= Seq(
"com.47deg" %% "github4s" % "0.24.0",
"net.jcazevedo" %% "moultingyaml" % "0.4.2",
"com.lihaoyi" %% "scalatags" % "0.9.3",
"com.sksamuel.scrimage" %% "scrimage-core" % "2.1.8"
"com.47deg" %% "github4s" % "0.24.0",
"net.jcazevedo" %% "moultingyaml" % "0.4.2",
"com.lihaoyi" %% "scalatags" % "0.9.3",
"com.sksamuel.scrimage" %% "scrimage-scala" % "4.0.12"
)
67 changes: 24 additions & 43 deletions src/main/scala/microsites/ioops/FileWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,13 @@

package microsites.ioops

import java.io.{File, FileOutputStream}
import java.io.File
import java.net.URL
import java.nio.file.Files.{copy => fcopy}
import java.nio.file.Path
import java.nio.file.{FileSystem, Files, Path}
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
import java.util.zip.ZipInputStream
import java.{util => ju}

import cats.instances.either._
import cats.instances.list._
import cats.syntax.either._
import cats.syntax.traverse._
import cats.implicits._
import microsites.Exceptions._
import syntax._

Expand Down Expand Up @@ -67,7 +63,7 @@ class FileWriter {

def safeCopy: Either[Throwable, Path] =
Either
.catchNonFatal(fcopy(input.toPath, output.toPath, REPLACE_EXISTING))
.catchNonFatal(Files.copy(input.toPath, output.toPath, REPLACE_EXISTING))

(for {
result <- createFile(output)
Expand All @@ -92,45 +88,30 @@ class FileWriter {
} yield paths
}

def copyJARResourcesTo(
jarUrl: URL,
output: String,
filter: String = ""
): Either[IOException, Unit] =
/** Copies files from an arbitrary FileSystem (dir, JAR, ZIP) defined at the listed URL */
def copyResourcesFromFileSystem(
fs: FileSystem,
outputPath: Path,
filters: List[String]
) = {
Either
.catchNonFatal {
output.fixPath.toFile.mkdir()

val zipIn = new ZipInputStream(jarUrl.openStream())

val buffer = new Array[Byte](1024)
Stream.continually(zipIn.getNextEntry).takeWhile(_ != null).foreach { entry =>
val newFile = IOUtils.file(output + File.separator + entry.getName)

(
entry.isDirectory,
!newFile.exists() &&
newFile.getAbsolutePath.startsWith(s"$output$filter")
) match {
case (true, true) => createDir(newFile)
case (true, _) =>
case (false, true) =>
createFile(newFile)

val fos = new FileOutputStream(newFile)

Stream.continually(zipIn.read(buffer)).takeWhile(_ != -1).foreach { count =>
fos.write(buffer, 0, count)
}

fos.close()
case _ =>
filters.foreach { filter =>
val fsPath = fs.getPath(filter)
if (Files.exists(fsPath)) {
Files.walk(fsPath).forEachOrdered { path =>
val dest = outputPath.resolve(path.toString.stripPrefix("/"))
try Option(dest.getParent()).foreach(Files.createDirectories(_))
finally Files.copy(path, dest, REPLACE_EXISTING)
}
}
}
}
.leftMap(e =>
IOException(s"Error copying resources from $jarUrl to directory $output", Some(e))
)
.leftMap { e =>
e.printStackTrace()
IOException(s"Error copying resources from JAR to directory $outputPath", Some(e))
}
}
}

object FileWriter extends FileWriter
98 changes: 68 additions & 30 deletions src/main/scala/microsites/util/MicrositeHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@
package microsites.util

import java.io.File
import java.net.URL

import cats.syntax.either._
import com.sksamuel.scrimage._
import java.net.{URI, URL}
import java.nio.file.{FileSystem, FileSystems, Paths}
import java.util.HashMap

import cats.implicits._
import com.sksamuel.scrimage.nio.ImageReader
import com.sksamuel.scrimage.ImmutableImage
import com.sksamuel.scrimage.implicits._
import microsites.util.YamlFormats._
import microsites._
import microsites.layouts._
Expand Down Expand Up @@ -55,31 +59,52 @@ class MicrositeHelper(config: MicrositeSettings) {
MicrositeFavicon(filename, s"${width}x$height")
}

def copyJAROrFolder(
jarUrl: URL,
output: String,
filter: String = ""
): Either[Exceptions.IOException, Any] =
copyJARResourcesTo(jarUrl, output, filter)
.orElse(copyFilesRecursively(jarUrl.getFile + filter, output + filter))
def copyResources(
resourcesJarFSOrPath: Either[FileSystem, java.nio.file.Path],
outputPath: java.nio.file.Path,
filters: List[String]
): Either[Exceptions.IOException, Any] = resourcesJarFSOrPath match {
case Left(fs) =>
println(s"Copying resources from sbt-microsite JAR")
val result = copyResourcesFromFileSystem(fs, outputPath, filters)
fs.close()
result
case Right(path) =>
println(s"Copying resources from local path $path")
filters.traverse { filter =>
copyFilesRecursively(path.toString, outputPath.toString)
}
}

def createResources(resourceManagedDir: File): List[File] = {

val targetDir: String = resourceManagedDir.getAbsolutePath.ensureFinalSlash
val pluginURL: URL = getClass.getProtectionDomain.getCodeSource.getLocation

copyJAROrFolder(pluginURL, s"$targetDir$jekyllDir/", "_sass")
copyJAROrFolder(pluginURL, s"$targetDir$jekyllDir/", "css")
copyJAROrFolder(pluginURL, s"$targetDir$jekyllDir/", "img")
copyJAROrFolder(pluginURL, s"$targetDir$jekyllDir/", "js")
copyJAROrFolder(pluginURL, s"$targetDir$jekyllDir/", "highlight/highlight.pack.js")
copyJAROrFolder(pluginURL, s"$targetDir$jekyllDir/", "highlight/LICENSE")
copyJAROrFolder(
pluginURL,
s"$targetDir$jekyllDir/",
s"highlight/styles/${config.visualSettings.highlightTheme}.css"
val pluginPath = Paths.get(pluginURL.getPath)
val outputPath = Paths.get(s"$targetDir$jekyllDir/")

val filters = List(
"_sass",
"css",
"img",
"js",
"highlight/highlight.pack.js",
"highlight/LICENSE",
s"highlight/styles/${config.visualSettings.highlightTheme}.css",
"plugins"
)
copyJAROrFolder(pluginURL, s"$targetDir$jekyllDir/", "plugins")

//If resources are in a JAR, we want to expose that as a FileSystem
//Otherwise we will just use the raw path
val pathOrFS: Either[FileSystem, java.nio.file.Path] =
if (pluginPath.getFileName.toString.endsWith(".jar")) {
val uri = URI.create("jar:file:" + pluginPath.toString)
FileSystems.newFileSystem(uri, new HashMap[String, Any]()).asLeft
} else {
pluginPath.asRight
}

copyResources(pathOrFS, outputPath, filters)

copyFilesRecursively(
config.fileLocations.micrositeImgDirectory.getAbsolutePath,
Expand Down Expand Up @@ -229,13 +254,26 @@ class MicrositeHelper(config: MicrositeSettings) {

createFile(sourceFile)

(faviconFilenames zip faviconSizes)
.map { case (name, size) =>
(new File(s"$targetDir$jekyllDir/img/$name"), size)
}
.map { case (file, (width, height)) =>
Image.fromFile(sourceFile.toFile).scaleTo(width, height).output(file)
}
//This is a dirty classloader hack to allow the latest version of Scrimage to work.
//This plugin's default classloader is limited and cannot load ImageReader instances.
//We get a different ClassLoader that will work, replace it, and then set it back after we're done.
//Will be fixed in Scrimage 4.1.0, see: https://github.com/sksamuel/scrimage/issues/217
sloshy marked this conversation as resolved.
Show resolved Hide resolved
val desiredCL: ClassLoader = classOf[ImageReader].getClassLoader
val currentCL = Thread.currentThread.getContextClassLoader()

try {
Thread.currentThread.setContextClassLoader(desiredCL)

(faviconFilenames zip faviconSizes)
.map { case (name, size) =>
(new File(s"$targetDir$jekyllDir/img/$name"), size)
}
.map { case (file, (width, height)) =>
ImmutableImage.loader.fromFile(sourceFile.toFile).scaleTo(width, height).output(file)
}
} finally
//Reset the classloader to what it was previously
Thread.currentThread.setContextClassLoader(currentCL)
}

def copyConfigurationFile(sourceDir: File, targetDir: File): Unit = {
Expand Down