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

feat: introduce FileSystem.unjarOnce #1249

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [3.4.2]
scala: [3.3.3]
java: [temurin@18]
runs-on: ${{ matrix.os }}
steps:
Expand Down Expand Up @@ -56,7 +56,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [3.4.2]
scala: [3.3.3]
java: [temurin@18]
runs-on: ${{ matrix.os }}
steps:
Expand Down
37 changes: 37 additions & 0 deletions common/shared/src/main/scala/org/specs2/io/FileSystem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@ case class FileSystem(logger: Logger) extends FilePathReader:
def mkdirs(path: FilePath): Operation[Unit] =
mkdirs(path.dir)

/** Unjaring the same thing over and over is inefficient. LRU cache to keep track of what was already done. */
private object UnjarLRUCache:
private var unjarLRUCache: Map[(URL, DirectoryPath, String), Long] = Map.empty
private val maxSize = 1000

/** Checks if the given parameters were already processed; if not immediately adds them to the cache. */
def alreadyUnjared(params: (URL, DirectoryPath, String)): Boolean =
UnjarLRUCache.synchronized:
val alreadyUnjared = unjarLRUCache.contains(params)
unjarLRUCache += params -> System.nanoTime
if !alreadyUnjared then clean()
alreadyUnjared

/** Clean up LRU entries until cache is at most max size. */
private def clean(): Unit = while unjarLRUCache.size > maxSize do unjarLRUCache -= unjarLRUCache.minBy(_._2)._1

/** Unjar the jar (or zip file) specified by "path" to the "dest" directory. Filters files which shouldn't be
* extracted with a regular expression. This is only done once per argument list (unless eventually evicted from LRU
* cache).
* @param jarUrl
* path of the jar file
* @param dest
* destination directory path
* @param regexFilter
* regular expression filtering files which shouldn't be extracted; the expression must capture the path of an
* entry as group 1 which will then be used relative to dirPath as target path for that entry
*
* @see
* [[unjar]]
*/
def unjarOnce(jarUrl: URL, dest: DirectoryPath, regexFilter: String): Operation[Unit] =
if UnjarLRUCache.alreadyUnjared((jarUrl, dest, regexFilter)) then Operation.ok(())
else unjar(jarUrl, dest, regexFilter)

/** Unjar the jar (or zip file) specified by "path" to the "dest" directory. Filters files which shouldn't be
* extracted with a regular expression.
* @param jarUrl
Expand All @@ -67,6 +101,9 @@ case class FileSystem(logger: Logger) extends FilePathReader:
* @param regexFilter
* regular expression filtering files which shouldn't be extracted; the expression must capture the path of an
* entry as group 1 which will then be used relative to dirPath as target path for that entry
*
* @see
* [[unjarOnce]]
*/
def unjar(jarUrl: URL, dest: DirectoryPath, regexFilter: String): Operation[Unit] =
val regex = compile(regexFilter)
Expand Down
2 changes: 1 addition & 1 deletion html/src/main/scala/org/specs2/reporter/HtmlPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ case class HtmlPrinter(env: Env, searchPage: SearchPage, logger: Logger = Consol
case Some(url) =>
val fs = env.fileSystem
if url.getProtocol.equalsIgnoreCase("jar") then
fs.unjar(jarOf(url), outputDir, s"^${quote(base.path)}(/${quote(src.path)}/.*)$$")
fs.unjarOnce(jarOf(url), outputDir, s"^${quote(base.path)}(/${quote(src.path)}/.*)$$")
else fs.copyDir(DirectoryPath.unsafe(url.toURI), outputDir / src)
case _ =>
val message = s"no resource found for path ${(base / src).path}"
Expand Down