From 5abe31fc745044ea6ed1661739694cd7be171777 Mon Sep 17 00:00:00 2001 From: Giorgio Garofalo Date: Sun, 3 Nov 2024 20:51:22 +0100 Subject: [PATCH] Fix media storage with absolute local paths --- .../context/hooks/MediaStorerHook.kt | 10 ++++++- .../iamgio/quarkdown/media/ResolvableMedia.kt | 3 ++- .../eu/iamgio/quarkdown/util/IOUtils.kt | 26 +++++++++++++++++++ .../kotlin/eu/iamgio/quarkdown/stdlib/Data.kt | 10 ++----- 4 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 core/src/main/kotlin/eu/iamgio/quarkdown/util/IOUtils.kt diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/context/hooks/MediaStorerHook.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/context/hooks/MediaStorerHook.kt index 42e286e8..42dbd819 100644 --- a/core/src/main/kotlin/eu/iamgio/quarkdown/context/hooks/MediaStorerHook.kt +++ b/core/src/main/kotlin/eu/iamgio/quarkdown/context/hooks/MediaStorerHook.kt @@ -6,6 +6,7 @@ import eu.iamgio.quarkdown.ast.base.inline.ReferenceImage import eu.iamgio.quarkdown.ast.iterator.AstIteratorHook import eu.iamgio.quarkdown.ast.iterator.ObservableAstIterator import eu.iamgio.quarkdown.context.MutableContext +import eu.iamgio.quarkdown.log.Log import eu.iamgio.quarkdown.media.storage.MutableMediaStorage import java.io.File @@ -27,7 +28,14 @@ class MediaStorerHook( override fun attach(iterator: ObservableAstIterator) { // Registers the media, wrapped in a link, to the media storage. - fun register(link: LinkNode) = storage.register(link.url, workingDirectory) + fun register(link: LinkNode) { + try { + storage.register(link.url, workingDirectory) + } catch (e: IllegalArgumentException) { + // If the media cannot be resolved, it is ignored and not stored. + Log.warn("Media cannot be resolved: ${link.url}") + } + } // Images are instantly registered. iterator.on { register(it.link) } diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/media/ResolvableMedia.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/media/ResolvableMedia.kt index 0bcc9202..8c56a591 100644 --- a/core/src/main/kotlin/eu/iamgio/quarkdown/media/ResolvableMedia.kt +++ b/core/src/main/kotlin/eu/iamgio/quarkdown/media/ResolvableMedia.kt @@ -1,5 +1,6 @@ package eu.iamgio.quarkdown.media +import eu.iamgio.quarkdown.util.IOUtils import eu.iamgio.quarkdown.util.toURLOrNull import java.io.File @@ -25,7 +26,7 @@ data class ResolvableMedia( // If the path is a URL, it is remote. path.toURLOrNull()?.let { return RemoteMedia(it) } - val file = workingDirectory?.let { File(it, path) } ?: File(path) + val file = IOUtils.resolvePath(path, workingDirectory) if (!file.exists()) throw IllegalArgumentException("Media path cannot be resolved: $path") if (file.isDirectory) throw IllegalArgumentException("Media is a directory: $path") diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/util/IOUtils.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/util/IOUtils.kt new file mode 100644 index 00000000..a6386d2f --- /dev/null +++ b/core/src/main/kotlin/eu/iamgio/quarkdown/util/IOUtils.kt @@ -0,0 +1,26 @@ +package eu.iamgio.quarkdown.util + +import java.io.File +import kotlin.io.path.Path + +/** + * Utility methods for file-based operations. + */ +object IOUtils { + /** + * Resolves a [File] located in [path], either relative or absolute. + * If the path is relative, the location is determined from the [workingDirectory]. + * @param path path of the file, either relative or absolute + * @param workingDirectory directory from which the file is resolved, in case the path is relative + * @return a [File] instance of the file + */ + fun resolvePath( + path: String, + workingDirectory: File?, + ): File = + if (workingDirectory != null && !Path(path).isAbsolute) { + File(workingDirectory, path) + } else { + File(path) + } +} diff --git a/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Data.kt b/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Data.kt index 620e1dcd..f5f780f2 100644 --- a/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Data.kt +++ b/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Data.kt @@ -11,8 +11,8 @@ import eu.iamgio.quarkdown.function.value.StringValue import eu.iamgio.quarkdown.function.value.data.Range import eu.iamgio.quarkdown.function.value.data.subList import eu.iamgio.quarkdown.function.value.wrappedAsValue +import eu.iamgio.quarkdown.util.IOUtils import java.io.File -import kotlin.io.path.Path /** * `Data` stdlib module exporter. @@ -37,13 +37,7 @@ internal fun file( requireExistance: Boolean = true, ): File { val workingDirectory = context.attachedPipeline?.options?.workingDirectory - - val file = - if (workingDirectory != null && !Path(path).isAbsolute) { - File(workingDirectory, path) - } else { - File(path) - } + val file = IOUtils.resolvePath(path, workingDirectory) if (requireExistance && !file.exists()) { throw IllegalArgumentException("File $file does not exist.")