Skip to content

Commit 9018fb5

Browse files
committed
Use java.nio.file.FileSystems to write to jar directly
1 parent 3442f98 commit 9018fb5

File tree

2 files changed

+70
-21
lines changed

2 files changed

+70
-21
lines changed

compiler/src/dotty/tools/backend/jvm/GenBCode.scala

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import dotty.tools.dotc.core.Phases.Phase
77
import dotty.tools.dotc.core.Names.TypeName
88

99
import scala.collection.mutable
10+
import scala.collection.JavaConverters._
1011
import scala.tools.asm.{ClassVisitor, CustomAttr, FieldVisitor, MethodVisitor}
1112
import scala.tools.nsc.backend.jvm._
1213
import dotty.tools.dotc
@@ -26,14 +27,15 @@ import Denotations._
2627
import Phases._
2728
import java.lang.AssertionError
2829
import java.io.{DataOutputStream, File => JFile}
29-
import dotty.tools.io.{Jar, File, Directory}
30+
import java.nio.file.{Files, FileSystem, FileSystems, Path => JPath}
31+
32+
import dotty.tools.io.{Directory, File, Jar}
3033

3134
import scala.tools.asm
3235
import scala.tools.asm.tree._
3336
import dotty.tools.dotc.util.{DotClass, Positions}
3437
import tpd._
3538
import StdNames._
36-
3739
import dotty.tools.io._
3840

3941
class GenBCode extends Phase {
@@ -47,40 +49,36 @@ class GenBCode extends Phase {
4749
superCallsMap.put(sym, old + calls)
4850
}
4951

52+
private[this] var jarFS: JarFS = _
53+
5054
def outputDir(implicit ctx: Context): AbstractFile = {
5155
val path = ctx.settings.outputDir.value
5256
if (path.isDirectory) new PlainDirectory(Directory(path))
53-
else new PlainFile(path)
57+
else {
58+
if (jarFS == null) {
59+
path.delete()
60+
jarFS = JarFS.create(path)
61+
}
62+
jarFS.getRoot()
63+
}
5464
}
5565

56-
private[this] var classOutput: AbstractFile = _
57-
5866
def run(implicit ctx: Context): Unit = {
5967
new GenBCodePipeline(entryPoints.toList,
60-
new DottyBackendInterface(classOutput, superCallsMap.toMap)(ctx))(ctx).run(ctx.compilationUnit.tpdTree)
68+
new DottyBackendInterface(outputDir, superCallsMap.toMap)(ctx))(ctx).run(ctx.compilationUnit.tpdTree)
6169
entryPoints.clear()
6270
}
6371

6472
override def runOn(units: List[CompilationUnit])(implicit ctx: Context) = {
65-
val output = outputDir
66-
if (output.isDirectory) {
67-
classOutput = output
68-
val res = super.runOn(units)
69-
classOutput = null
70-
res
71-
} else {
72-
assert(output.hasExtension("jar"))
73-
classOutput = new PlainDirectory(Path(Path(output.file).parent + "/tmp-jar-" + System.currentTimeMillis().toHexString).createDirectory())
74-
val res = super.runOn(units)
75-
Jar.create(new File(ctx.settings.outputDir.value.jfile), new Directory(classOutput.file), mainClass = "")
76-
classOutput.delete()
77-
classOutput = null
78-
res
73+
try super.runOn(units)
74+
finally if (jarFS ne null) {
75+
try { jarFS.close() } catch { case _: Throwable => }
76+
jarFS = null
7977
}
8078
}
8179
}
8280

83-
class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInterface)(implicit val ctx: Context) extends BCodeSyncAndTry{
81+
class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInterface)(implicit val ctx: Context) extends BCodeSyncAndTry {
8482

8583
var tree: Tree = _
8684

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package dotty.tools
2+
package io
3+
4+
import java.nio.file.{FileSystem, FileSystems}
5+
import java.nio.file.Files
6+
7+
import java.util.jar._
8+
9+
import scala.collection.JavaConverters._
10+
11+
class JarFS private (private[this] var jarFS: FileSystem) {
12+
13+
def getRoot(): AbstractFile = {
14+
val root = jarFS.getRootDirectories.iterator().next()
15+
new JarFS.JarDirectory(root)(jarFS)
16+
}
17+
18+
def close() = {
19+
jarFS.close()
20+
jarFS = null
21+
}
22+
}
23+
24+
object JarFS {
25+
26+
def create(path: Path): JarFS = {
27+
assert(path.extension == "jar")
28+
val env = Map("create" -> "true").asJava
29+
val jarUri = java.net.URI.create("jar:file:" + path.toAbsolute.path)
30+
new JarFS(FileSystems.newFileSystem(jarUri, env))
31+
}
32+
33+
private class JarDirectory(path: JPath)(jarFS: FileSystem) extends PlainDirectory(new Directory(path)) {
34+
override def name = "<jar-dir>"
35+
override def file = throw new UnsupportedOperationException
36+
override def fileNamed(name: String): AbstractFile = new JarFile(pathTo(name))
37+
override def subdirectoryNamed(name: String): AbstractFile = new JarDirectory(pathTo(name))(jarFS)
38+
private def pathTo(name: String): JPath =
39+
jarFS.getPath(if (path.toString == "/") name else path.resolve(name).toString)
40+
}
41+
42+
private class JarFile(path: JPath) extends PlainFile(new File(path)) {
43+
override def name = "<jar-file>"
44+
override def file = throw new UnsupportedOperationException
45+
override def output = {
46+
if (path.getParent ne null)
47+
Files.createDirectories(path.getParent)
48+
Files.newOutputStream(path)
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)