Skip to content
Snippets Groups Projects
Verified Commit 6b04722a authored by Rico Bergmann's avatar Rico Bergmann
Browse files

#7 - Refactor SModelFSWriter to use external services

Compilation, JAR packaging and classpath access will now be done through
dedicated external services rather than in the SModelFSWriter itself.

Closes #7.
parent dbc7157b
No related branches found
No related tags found
1 merge request!2Publish v0.1
package org.rosi_project.model_sync.generator.env
import java.io.PrintWriter
import scala.reflect.io.File
import scala.tools.nsc.reporters.ConsoleReporter
import scala.tools.nsc.{GenericRunnerSettings, Global, Settings}
/** Utility to compile all set of Scala source files to Java byte code.
*
* @param outDir the directory where the compiled files should placed
* @author Rico Bergmann
*/
class FilesCompiler(outDir: File) {
/** Compiles all given files.
*/
def run(filesToCompile: List[File]): Unit = {
// see: https://stackoverflow.com/a/20323371/5161760
val out = new PrintWriter(System.out)
val compilationSettings: Settings = new GenericRunnerSettings(out.println)
// just re-use the whole classpath
compilationSettings.classpath.value = JClassPath.adaptClassPathToOSEnv(JClassPath.fetchCurrentClassPath).distinct.mkString(File.pathSeparator)
println(s"Using classpath ${compilationSettings.classpath.value}")
compilationSettings.outdir.value = outDir.toAbsolute.toString
val reporter = new ConsoleReporter(compilationSettings)
val compiler = new Global(compilationSettings, reporter)
val runner = new compiler.Run
runner.compile(filesToCompile.map(_.toAbsolute.toString))
}
}
package org.rosi_project.model_sync.generator.env
import java.net.URLClassLoader
/** Utility to provide high level access to the application's ''classpath'' as well as some basic
* transformations.
*
* @author Rico Bergmann
*/
object JClassPath {
/** Provides a platform-specific version of the ''classpath''. All entries may than be resolved as
* files on the current OS.
*
* @param cp the ''classpath'' to adapt
*/
def adaptClassPathToOSEnv(cp: List[String]): List[String] = {
sys.props("os.name").toLowerCase match {
case win if win contains "windows" =>
cp.map(entry => {
val WinUrl = """file:/(.*)""".r
entry match {
case WinUrl(path) => path
case p => p
}
}).map(_.replaceAll("/", "\\\\").replaceAll("%20", " "))
case unix =>
val UnixUrl = """file:(.*)""".r
cp.map {
case UnixUrl(path) => path
case p => p
}
}
}
/** Gets the ''classpath'' as it is currently used by this application.
*/
def fetchCurrentClassPath: List[String] = {
val ctxLoader = Thread.currentThread().getContextClassLoader
ctxLoader match {
case urlCL: URLClassLoader =>
urlCL.getURLs.toList.map {
_.toString
}
case wrappedCL =>
wrappedCL.getParent match {
case urlCL: URLClassLoader =>
urlCL.getURLs.toList.map {
_.toString
}
}
case something => sys.error(s"Could not unwrap class loader: $something")
}
}
}
package org.rosi_project.model_sync.generator.env
import java.io.{BufferedInputStream, FileInputStream, FileOutputStream}
import java.util.jar.{Attributes, JarEntry, JarOutputStream, Manifest}
import scala.reflect.io.{Directory, File}
import scala.util.control.Breaks.{break, breakable}
/** Utility to put all files from some directory into a JAR.
*
* This will simply copy all files from the source directory into the JAR at the target directory.
*
* @param inputDir the directory where all source files reside.
* @param outputDir the target directory where the JAR will be created
* @param jarName the name of the JAR file to create
* @author Rico Bergmann
*/
class JarPackager(inputDir: File, outputDir: File, jarName: String = "model.jar") {
/** Starts the packaging process.
*/
def run(): Unit = {
// see: https://stackoverflow.com/a/1281295/5161760
val mf = new Manifest
mf.getMainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0")
val targetJar = new JarOutputStream(new FileOutputStream(outputDir + File.separator + jarName), mf)
var filesToAdd: List[java.io.File] = inputDir.jfile.listFiles.toList
while (filesToAdd.nonEmpty) {
val file = filesToAdd.head
var fname = file.getAbsolutePath.replace(inputDir.jfile.getAbsolutePath + File.separator, "").replaceAll("\\\\", "/")
println(s"Adding to JAR: $fname")
if (file.isDirectory) {
if (!fname.endsWith("/")) {
fname += "/"
}
filesToAdd ++= file.listFiles.toList
val entry = new JarEntry(fname)
entry.setTime(file.lastModified)
targetJar.putNextEntry(entry)
targetJar.closeEntry()
} else {
val entry = new JarEntry(fname)
entry.setTime(file.lastModified)
targetJar.putNextEntry(entry)
val in = new BufferedInputStream(new FileInputStream(file))
var buffer = new Array[Byte](1024)
breakable {
while (true) {
val bytesRead = in.read(buffer)
if (bytesRead == -1) {
break
}
targetJar.write(buffer, 0, bytesRead)
}
}
targetJar.closeEntry()
in.close()
}
filesToAdd = filesToAdd.tail
}
targetJar.close()
}
}
...@@ -8,6 +8,7 @@ import java.util.jar.{Attributes, JarEntry, JarOutputStream, Manifest} ...@@ -8,6 +8,7 @@ import java.util.jar.{Attributes, JarEntry, JarOutputStream, Manifest}
import org.rosi_project.model_sync.generator.ModelConfig import org.rosi_project.model_sync.generator.ModelConfig
import org.rosi_project.model_sync.generator.acr_model._ import org.rosi_project.model_sync.generator.acr_model._
import org.rosi_project.model_sync.generator.env.{FilesCompiler, JarPackager}
import scala.reflect.io.{File, Path} import scala.reflect.io.{File, Path}
import scala.tools.nsc.reporters.ConsoleReporter import scala.tools.nsc.reporters.ConsoleReporter
...@@ -50,17 +51,7 @@ class SModelFSWriter( ...@@ -50,17 +51,7 @@ class SModelFSWriter(
println(s"... Wrote files (sources) $sFilesToCompile") println(s"... Wrote files (sources) $sFilesToCompile")
println("... Starting compilation") println("... Starting compilation")
// see: https://stackoverflow.com/a/20323371/5161760 new FilesCompiler(workingDir).run(sFilesToCompile)
val out = new PrintWriter(System.out)
val compilationSettings: Settings = new GenericRunnerSettings(out.println)
// just re-use the whole classpath
compilationSettings.classpath.value = adaptClassPathToOSEnv(fetchCurrentClassPath).distinct.mkString(File.pathSeparator)
println(s"Using classpath ${compilationSettings.classpath.value}")
compilationSettings.outdir.value = workingDir.toAbsolute.toString
val reporter = new ConsoleReporter(compilationSettings)
val compiler = new Global(compilationSettings, reporter)
val runner = new compiler.Run
runner.compile(sFilesToCompile.map(_.toAbsolute.toString))
println("... Compilation done") println("... Compilation done")
if (!keepClassFiles) { if (!keepClassFiles) {
...@@ -73,50 +64,7 @@ class SModelFSWriter( ...@@ -73,50 +64,7 @@ class SModelFSWriter(
} }
println("... Generating JAR") println("... Generating JAR")
// see: https://stackoverflow.com/a/1281295/5161760 new JarPackager(workingDir, outputDir.toFile).run()
val mf = new Manifest
mf.getMainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0")
val targetJar = new JarOutputStream(new FileOutputStream(outputDir + File.separator + "model.jar"), mf)
var filesToAdd: List[java.io.File] = workingDir.jfile.listFiles.toList
while (filesToAdd.nonEmpty) {
val file = filesToAdd.head
var fname = file.getAbsolutePath.replace(workingDir.jfile.getAbsolutePath + File.separator, "").replaceAll("\\\\", "/")
println(s"Adding to JAR: $fname")
if (file.isDirectory) {
if (!fname.endsWith("/")) {
fname += "/"
}
filesToAdd ++= file.listFiles.toList
val entry = new JarEntry(fname)
entry.setTime(file.lastModified)
targetJar.putNextEntry(entry)
targetJar.closeEntry()
} else {
val entry = new JarEntry(fname)
entry.setTime(file.lastModified)
targetJar.putNextEntry(entry)
val in = new BufferedInputStream(new FileInputStream(file))
var buffer = new Array[Byte](1024)
breakable {
while (true) {
val bytesRead = in.read(buffer)
if (bytesRead == -1) {
break
}
targetJar.write(buffer, 0, bytesRead)
}
}
targetJar.closeEntry()
in.close()
}
filesToAdd = filesToAdd.tail
}
targetJar.close()
println("... Done") println("... Done")
} }
...@@ -150,50 +98,6 @@ class SModelFSWriter( ...@@ -150,50 +98,6 @@ class SModelFSWriter(
*/ */
private def pckg2Path(pckg: String): Path = Path(pckg.replace(".", File.separator)) private def pckg2Path(pckg: String): Path = Path(pckg.replace(".", File.separator))
/** Gets the ''classpath'' as it is currently used by this application.
*/
private def fetchCurrentClassPath: List[String] = {
val ctxLoader = Thread.currentThread().getContextClassLoader
ctxLoader match {
case urlCL: URLClassLoader =>
urlCL.getURLs.toList.map {
_.toString
}
case wrappedCL =>
wrappedCL.getParent match {
case urlCL: URLClassLoader =>
urlCL.getURLs.toList.map {
_.toString
}
case something => sys.error(s"Could not unwrap class loader: $something")
}
}
}
/** Provides a platform-specific version of the ''classpath''. All entries may than be resolved as
* files on the current OS.
*
* @param cp the ''classpath'' to adapt
*/
private def adaptClassPathToOSEnv(cp: List[String]): List[String] = {
sys.props("os.name").toLowerCase match {
case win if win contains "windows" =>
cp.map(entry => {
val WinUrl = """file:/(.*)""".r
entry match {
case WinUrl(path) => path
case p => p
}
}).map(_.replaceAll("/", "\\\\").replaceAll("%20", " "))
case unix =>
val UnixUrl = """file:(.*)""".r
cp.map {
case UnixUrl(path) => path
case p => p
}
}
}
private def collectAllModelImages(modelConfig: ModelConfig, workingPath: jio.File): List[jio.File] = { private def collectAllModelImages(modelConfig: ModelConfig, workingPath: jio.File): List[jio.File] = {
var images: List[jio.File] = List.empty var images: List[jio.File] = List.empty
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment