-
-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
227 additions
and
149 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
...als-platform/.jvm/src/main/scala/izumi/fundamentals/platform/files/ExecutableSearch.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package izumi.fundamentals.platform.files | ||
|
||
import izumi.fundamentals.platform.os.{IzOs, OsType} | ||
|
||
import java.nio.file.{Path, Paths} | ||
|
||
trait ExecutableSearch { | ||
def haveExecutables(names: String*): Boolean = { | ||
names.forall(which(_).nonEmpty) | ||
} | ||
|
||
def which(name: String, morePaths: Seq[String] = Seq.empty): Option[Path] = { | ||
find(binaryNameCandidates(name), IzOs.path ++ morePaths) | ||
} | ||
|
||
def whichAll(name: String, morePaths: Seq[String] = Seq.empty): Iterable[Path] = { | ||
findAll(binaryNameCandidates(name), IzOs.path ++ morePaths) | ||
} | ||
|
||
private def find(candidates: Seq[String], paths: Seq[String]): Option[Path] = { | ||
paths.view | ||
.flatMap { | ||
p => | ||
candidates.map(ext => Paths.get(p).resolve(ext)) | ||
} | ||
.find { | ||
p => | ||
p.toFile.exists() | ||
} | ||
} | ||
|
||
private def findAll(candidates: Seq[String], paths: Seq[String]): Iterable[Path] = { | ||
paths.view | ||
.flatMap { | ||
p => | ||
candidates.map(ext => Paths.get(p).resolve(ext)) | ||
} | ||
.filter { | ||
p => | ||
p.toFile.exists() | ||
} | ||
} | ||
|
||
private def binaryNameCandidates(name: String): Seq[String] = { | ||
IzOs.osType match { | ||
case OsType.Windows => | ||
Seq("exe", "com", "bat").map(ext => s"$name.$ext") | ||
case _ => | ||
Seq(name) | ||
} | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
...ntals-platform/.jvm/src/main/scala/izumi/fundamentals/platform/files/FileAttributes.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package izumi.fundamentals.platform.files | ||
|
||
import izumi.fundamentals.platform.time.IzTime | ||
|
||
import java.io.File | ||
import java.time.LocalDateTime | ||
|
||
trait FileAttributes { this: FileSearch => | ||
/** Unsafe, will recursively iterate the whole directory | ||
*/ | ||
def getLastModifiedRecursively(directory: File): Option[LocalDateTime] = { | ||
import IzTime.* | ||
|
||
if (!directory.exists()) { | ||
return None | ||
} | ||
|
||
if (directory.isDirectory) { | ||
val dmt = directory.lastModified().asEpochMillisLocal | ||
|
||
val fmt = walk(directory).map(_.toFile.lastModified().asEpochMillisLocal).toSeq | ||
|
||
Some((dmt +: fmt).max) | ||
} else { | ||
Some(directory.lastModified().asEpochMillisLocal) | ||
} | ||
} | ||
|
||
} |
16 changes: 16 additions & 0 deletions
16
...ndamentals-platform/.jvm/src/main/scala/izumi/fundamentals/platform/files/FileReads.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package izumi.fundamentals.platform.files | ||
|
||
import java.io.File | ||
import java.nio.charset.StandardCharsets | ||
import java.nio.file.Path | ||
|
||
trait FileReads { | ||
def readString(path: Path): String = { | ||
import java.nio.file.Files | ||
new String(Files.readAllBytes(path), StandardCharsets.UTF_8) | ||
} | ||
|
||
def readString(file: File): String = { | ||
readString(file.toPath) | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
...damentals-platform/.jvm/src/main/scala/izumi/fundamentals/platform/files/FileSearch.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package izumi.fundamentals.platform.files | ||
|
||
import java.io.File | ||
import java.nio.file.{Files, Path} | ||
import scala.jdk.CollectionConverters.* | ||
|
||
trait FileSearch { | ||
def walk(directory: Path): Iterator[Path] = { | ||
Files.walk(directory).iterator().asScala | ||
} | ||
|
||
def walk(directory: File): Iterator[Path] = { | ||
walk(directory.toPath) | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
...ndamentals-platform/.jvm/src/main/scala/izumi/fundamentals/platform/files/FsRefresh.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package izumi.fundamentals.platform.files | ||
|
||
import izumi.fundamentals.platform.language.Quirks | ||
|
||
import java.nio.file.{Files, Path} | ||
|
||
trait FsRefresh { this: RecursiveFileRemovals => | ||
def recreateDirs(paths: Path*): Unit = { | ||
paths.foreach(recreateDir) | ||
} | ||
|
||
def recreateDir(path: Path): Unit = { | ||
val asFile = path.toFile | ||
|
||
if (asFile.exists()) { | ||
erase(path) | ||
} | ||
|
||
Quirks.discard(asFile.mkdirs()) | ||
} | ||
|
||
def refreshSymlink(symlink: Path, target: Path): Unit = { | ||
Quirks.discard(symlink.toFile.delete()) | ||
Quirks.discard(Files.createSymbolicLink(symlink, target.toFile.getCanonicalFile.toPath)) | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
...fundamentals-platform/.jvm/src/main/scala/izumi/fundamentals/platform/files/Homedir.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package izumi.fundamentals.platform.files | ||
|
||
import java.nio.file.{Path, Paths} | ||
|
||
trait Homedir { | ||
def home(): Path = { | ||
Paths.get(System.getProperty("user.home")) | ||
} | ||
|
||
def homedir(): String = { | ||
home().toFile.getCanonicalPath | ||
} | ||
} |
145 changes: 10 additions & 135 deletions
145
...fundamentals-platform/.jvm/src/main/scala/izumi/fundamentals/platform/files/IzFiles.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,144 +1,19 @@ | ||
package izumi.fundamentals.platform.files | ||
|
||
import java.io.{File, IOException} | ||
import java.net.URI | ||
import java.nio.charset.StandardCharsets | ||
import java.nio.file._ | ||
import java.nio.file.attribute.BasicFileAttributes | ||
import java.time.LocalDateTime | ||
import java.util.stream.Collectors | ||
|
||
import izumi.fundamentals.platform.language.Quirks | ||
import izumi.fundamentals.platform.os.{IzOs, OsType} | ||
import izumi.fundamentals.platform.time.IzTime | ||
|
||
import scala.jdk.CollectionConverters._ | ||
import java.nio.file.* | ||
import scala.annotation.nowarn | ||
import scala.jdk.CollectionConverters.* | ||
import scala.util.Try | ||
|
||
object IzFiles { | ||
def homedir(): String = { | ||
Paths.get(System.getProperty("user.home")).toFile.getCanonicalPath | ||
} | ||
|
||
def getFs(uri: URI): Try[FileSystem] = synchronized { | ||
@nowarn("msg=Unused import") | ||
object IzFiles extends RecursiveFileRemovals with FileSearch with FsRefresh with FileReads with ExecutableSearch with Homedir with FileAttributes { | ||
def getFs(uri: URI, loader: ClassLoader): Try[FileSystem] = { | ||
// this is like DCL, there might be races but we have no tool to prevent them | ||
// so first we try to get a filesystem, if it's not there we try to create it, there might be a race so it can fail, so we try to get again | ||
Try(FileSystems.getFileSystem(uri)) | ||
.recover { | ||
case _ => | ||
FileSystems.newFileSystem(uri, Map.empty[String, Any].asJava) | ||
} | ||
} | ||
|
||
def getLastModified(directory: File): Option[LocalDateTime] = { | ||
import IzTime._ | ||
|
||
if (!directory.exists()) { | ||
return None | ||
} | ||
|
||
if (directory.isDirectory) { | ||
val dmt = directory.lastModified().asEpochMillisLocal | ||
|
||
val fmt = walk(directory).map(_.toFile.lastModified().asEpochMillisLocal) | ||
|
||
Some((dmt +: fmt).max) | ||
} else { | ||
Some(directory.lastModified().asEpochMillisLocal) | ||
} | ||
} | ||
|
||
def walk(directory: File): Seq[Path] = { | ||
Files.walk(directory.toPath).collect(Collectors.toList()).asScala.toSeq | ||
} | ||
|
||
def recreateDirs(paths: Path*): Unit = { | ||
paths.foreach(recreateDir) | ||
} | ||
|
||
def readString(path: Path): String = { | ||
import java.nio.file.Files | ||
new String(Files.readAllBytes(path), StandardCharsets.UTF_8) | ||
} | ||
|
||
def readString(file: File): String = { | ||
readString(file.toPath) | ||
} | ||
|
||
def recreateDir(path: Path): Unit = { | ||
val asFile = path.toFile | ||
|
||
if (asFile.exists()) { | ||
removeDir(path) | ||
} | ||
|
||
Quirks.discard(asFile.mkdirs()) | ||
} | ||
|
||
def removeDir(root: Path): Unit = { | ||
val _ = Files.walkFileTree( | ||
root, | ||
new SimpleFileVisitor[Path] { | ||
override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = { | ||
Files.delete(file) | ||
FileVisitResult.CONTINUE | ||
} | ||
|
||
override def postVisitDirectory(dir: Path, exc: IOException): FileVisitResult = { | ||
Files.delete(dir) | ||
FileVisitResult.CONTINUE | ||
} | ||
|
||
}, | ||
) | ||
} | ||
|
||
def refreshSymlink(symlink: Path, target: Path): Unit = { | ||
Quirks.discard(symlink.toFile.delete()) | ||
Quirks.discard(Files.createSymbolicLink(symlink, target.toFile.getCanonicalFile.toPath)) | ||
} | ||
|
||
def haveExecutables(names: String*): Boolean = { | ||
names.forall(which(_).nonEmpty) | ||
} | ||
|
||
def which(name: String, morePaths: Seq[String] = Seq.empty): Option[Path] = { | ||
find(binaryNameCandidates(name), IzOs.path ++ morePaths) | ||
} | ||
|
||
def whichAll(name: String, morePaths: Seq[String] = Seq.empty): Iterable[Path] = { | ||
findAll(binaryNameCandidates(name), IzOs.path ++ morePaths) | ||
} | ||
|
||
private def binaryNameCandidates(name: String): Seq[String] = { | ||
IzOs.osType match { | ||
case OsType.Windows => | ||
Seq("exe", "com", "bat").map(ext => s"$name.$ext") | ||
case _ => | ||
Seq(name) | ||
} | ||
} | ||
|
||
def find(candidates: Seq[String], paths: Seq[String]): Option[Path] = { | ||
paths.view | ||
.flatMap { | ||
p => | ||
candidates.map(ext => Paths.get(p).resolve(ext)) | ||
} | ||
.find { | ||
p => | ||
p.toFile.exists() | ||
} | ||
} | ||
|
||
def findAll(candidates: Seq[String], paths: Seq[String]): Iterable[Path] = { | ||
paths.view | ||
.flatMap { | ||
p => | ||
candidates.map(ext => Paths.get(p).resolve(ext)) | ||
} | ||
.filter { | ||
p => | ||
p.toFile.exists() | ||
} | ||
.orElse(Try(FileSystems.newFileSystem(uri, Map.empty[String, Any].asJava, loader))) | ||
.orElse(Try(FileSystems.getFileSystem(uri))) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
...latform/.jvm/src/main/scala/izumi/fundamentals/platform/files/RecursiveFileRemovals.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package izumi.fundamentals.platform.files | ||
|
||
import java.io.{File, IOException} | ||
import java.nio.file.attribute.BasicFileAttributes | ||
import java.nio.file.{FileVisitResult, Files, Path, SimpleFileVisitor} | ||
|
||
trait RecursiveFileRemovals { | ||
def erase(root: Path): Unit = { | ||
val _ = Files.walkFileTree( | ||
root, | ||
new SimpleFileVisitor[Path] { | ||
override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = { | ||
Files.delete(file) | ||
FileVisitResult.CONTINUE | ||
} | ||
|
||
override def postVisitDirectory(dir: Path, exc: IOException): FileVisitResult = { | ||
Files.delete(dir) | ||
FileVisitResult.CONTINUE | ||
} | ||
|
||
}, | ||
) | ||
} | ||
|
||
def erase(root: File): Unit = { | ||
erase(root.toPath) | ||
} | ||
|
||
@deprecated("use IzFiles.erase") | ||
def removeDir(root: Path): Unit = { | ||
erase(root) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.