-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Use nio.Path instead of io.File to properly support PlainNioFile #3395
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
Use nio.Path instead of io.File to properly support PlainNioFile #3395
Conversation
|
The CI should not have passed on 72fa00d. |
|
|
||
| /** Returns the path of this abstract file in a canonical form. */ | ||
| def canonicalPath: String = if (file == null) path else file.getCanonicalPath | ||
| def canonicalPath: String = if (jpath == null) path else jpath.toFile.getCanonicalPath |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is equivalent to jpath.normalize.toString
|
|
||
| /** Returns the underlying File if any and null otherwise. */ | ||
| def file: JFile | ||
| def file: JFile = try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we should remove this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That will be for next step. That might need changes outside of the Path/File/Directory abstractions. I would prefer to keep the changes only inside these abstractions for this first step.
| val path = jpath.resolve(name) | ||
| try { | ||
| if (isDir) Files.createDirectories(path) | ||
| else Files.createFile(path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not create intermediate directories if necessary. We need to make sure it behaves as before
| if (isDir) Files.createDirectories(path) | ||
| else Files.createFile(path) | ||
| } catch { | ||
| case _: FileAlreadyExistsException => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it should never happen, otherwise lookupName would not have returned null
| override def addExtension(ext: String): File = super.addExtension(ext).toFile | ||
| override def toAbsolute: File = if (isAbsolute) this else super.toAbsolute.toFile | ||
| override def toDirectory: Directory = new Directory(jfile) | ||
| override def toDirectory: Directory = new Directory(jfile.toPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not simply new Directory(jpath)?
| else Directory(".") // a dir under pwd | ||
| case x => | ||
| Directory(x) | ||
| Directory(x.toFile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should probably be a constructor that takes a JPath. And I think we should remove the JFile constructor
| } | ||
| f.delete() | ||
| def deleteRecursively(): Boolean = deleteRecursively(jpath) | ||
| private def deleteRecursively(p: JPath): Boolean = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the proper way to delete recursively with nio is:
def deleteRecursively(dir: Path): Unit = if (Files.exists(dir)) {
Files.walkFileTree(dir, new SimpleFileVisitor[Path]() {
override def visitFile(file: Path, attrs: BasicFileAttributes) = {
Files.delete(file)
FileVisitResult.CONTINUE
}
override def postVisitDirectory(dir: Path, exc: IOException) = {
Files.delete(dir)
FileVisitResult.CONTINUE
}
})Not sure what should be the behavior if the path does not exist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as before:
def deleteRecursively(dir: Path): Unit = if (Files.exists(dir)) {
Files.walkFileTree(dir, new SimpleFileVisitor[Path]() {
override def visitFile(file: Path, attrs: BasicFileAttributes) = {
Files.delete(file)
FileVisitResult.CONTINUE
}
override def postVisitDirectory(dir: Path, exc: IOException) = {
Files.delete(dir)
FileVisitResult.CONTINUE
}
})
| } | ||
|
|
||
| private def tryCreate(create: => JPath): Boolean = | ||
| try { create; true } catch { case _: FileAlreadyExistsException => false } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Semantic is different for something like foo/bar/ if foo does not exist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we saw together the semantics are the same. In the example, an IOException would be thrown in both implementations.
| } | ||
|
|
||
| private def delete(path: JPath): Boolean = | ||
| try { Files.delete(path); true } catch { case _: DirectoryNotEmptyException | _: NoSuchFileException => false } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use deleteIfExists and not catch NoSuchFileException
| } | ||
| /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ | ||
| final class FileZipArchive(file: JFile) extends ZipArchive(file) { | ||
| final class FileZipArchive(file: JFile) extends ZipArchive(file.toPath) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't you use a JPath here instead?
.drone.yml
Outdated
| - cp -R . /tmp/1/ && cd /tmp/1/ | ||
| - ./project/scripts/sbt compile # to ensure that side projects (such as dotty doc) compile | ||
| - ./project/scripts/sbt testAll | ||
| - ./project/scripts/sbt ";dotty-bench/jmh:run 1 1 tests/run/arrays.scala" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was meant to make sure that dotty-bench compiles. Should it be part of dottyRoot so that we can get rid of this line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be a solution
|
In
|
|
|
| defaultIncludes ++ userDefinedIncludes | ||
| } | ||
|
|
||
| private def toSourceFile(f: JFile): SourceFile = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably be changed to take a JPath instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be for another PR.
|
I don't understand what's going on in this PR. What's the motivation? |
e2222dd to
a914812
Compare
|
test performance please |
|
performance test scheduled: 2 job(s) in queue, 1 running. |
a914812 to
813d376
Compare
|
I still would like to know the rationale behind this PR :). Also it's likely incomplete, ExtractDependencies#recordDependency needs an extra case to handle PlainNioFiles: https://github.com/dotty-staging/dotty/blob/813d376d78ccf752b480882fbcb58cd6a35431a4/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala#L98, otherwise incremental compilation will be broken |
813d376 to
2694273
Compare
|
@smarter I believe writing to a jar required using the |
|
ExtractDependencies#recordDependency won't have any problems, I removed |
|
test performance please |
|
performance test scheduled: 2 job(s) in queue, 1 running. |
|
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/3395/ to see the changes. Benchmarks is based on merging with master (cbb481c) |
1 similar comment
|
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/3395/ to see the changes. Benchmarks is based on merging with master (cbb481c) |
|
@retronym is there any reason scalac still has PlainFile and PlainNioFile or would the kind of refactoring done here make sense in scalac too? |
|
I added PlainNioFile as a minimal bridge from the AbtractFile to nio, as a
means to support JDK’s jrt:// filesystem. I think AbstractFile should
probably be removed from compiler APIs entirely in favour of direct use
NIO. A bit of experimentation is needed to make sure we can still support
in memory use cases (via a custom in memory filesystemprovider)
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still methods in File are implemented in term of jfile
| jfile.listFiles match { | ||
| case null => Iterator.empty | ||
| case xs => xs.iterator map Path.apply | ||
| def list: Iterator[Path] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be lazy
if (isDirectory) Files.list(jpath).iterator.asScala.map(Path.apply)
else Iterator.empty| def onlyFiles(xs: Iterator[Path]): Iterator[File] = xs filter (_.isFile) map (_.toFile) | ||
|
|
||
| def roots: List[Path] = java.io.File.listRoots().toList map Path.apply | ||
| def roots: List[Path] = java.io.File.listRoots().toList.map(r => Path.apply(r.toPath)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FileSystems.getDefault().getRootDirectories()?
| def createFile(failIfExists: Boolean = false): File = { | ||
| val res = jfile.createNewFile() | ||
| val res = tryCreate(Files.createFile(jpath)) | ||
| jfile.createNewFile() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be here?
| } | ||
| f.delete() | ||
| def deleteRecursively(): Boolean = deleteRecursively(jpath) | ||
| private def deleteRecursively(p: JPath): Boolean = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as before:
def deleteRecursively(dir: Path): Unit = if (Files.exists(dir)) {
Files.walkFileTree(dir, new SimpleFileVisitor[Path]() {
override def visitFile(file: Path, attrs: BasicFileAttributes) = {
Files.delete(file)
FileVisitResult.CONTINUE
}
override def postVisitDirectory(dir: Path, exc: IOException) = {
Files.delete(dir)
FileVisitResult.CONTINUE
}
})
| * @param file a File | ||
| * @return A ZipArchive if `file` is a readable zip file, otherwise null. | ||
| */ | ||
| def fromFile(file: File): FileZipArchive = fromFile(file.jfile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add fromPath and make the other delegate to it
bfc9784 to
3108499
Compare
|
test performance please |
|
performance test scheduled: 2 job(s) in queue, 1 running. |
|
|
||
| /** Obtains a OutputStream. */ | ||
| def outputStream(append: Boolean = false) = new FileOutputStream(jfile, append) | ||
| def outputStream(append: Boolean = false) = Files.newOutputStream(jpath, APPEND) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
APPEND?
| def fromFile(file: File): FileZipArchive = fromPath(file.jpath) | ||
| def fromPath(jpath: JPath): FileZipArchive = | ||
| try { new FileZipArchive(jpath) } | ||
| catch { case _: IOException => null } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what can throw an IOException here
|
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/3395/ to see the changes. Benchmarks is based on merging with master (22ff8a4) |
|
Also, I think you can implement |
5dea2a7 to
5065cf2
Compare
|
test performance please |
|
performance test scheduled: 1 job(s) in queue, 0 running. |
|
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/3395/ to see the changes. Benchmarks is based on merging with master (22ff8a4) |
|
test performance please |
|
performance test scheduled: 1 job(s) in queue, 1 running. |
|
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/3395/ to see the changes. Benchmarks is based on merging with master (45387e2) |
|
test performance please |
|
performance test scheduled: 1 job(s) in queue, 0 running. |
|
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/3395/ to see the changes. Benchmarks is based on merging with master (45387e2) |
No description provided.