diff --git a/vgo/src/main/kotlin/com/jzbrooks/vgo/Vgo.kt b/vgo/src/main/kotlin/com/jzbrooks/vgo/Vgo.kt index 78ffa043..2e4bda8a 100644 --- a/vgo/src/main/kotlin/com/jzbrooks/vgo/Vgo.kt +++ b/vgo/src/main/kotlin/com/jzbrooks/vgo/Vgo.kt @@ -16,8 +16,13 @@ import org.w3c.dom.Document import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.File +import java.nio.file.Path import java.nio.file.Paths import javax.xml.parsers.DocumentBuilderFactory +import kotlin.io.path.exists +import kotlin.io.path.isDirectory +import kotlin.io.path.isRegularFile +import kotlin.io.path.isSameFileAs import kotlin.math.absoluteValue import kotlin.math.roundToInt @@ -53,17 +58,7 @@ class Vgo( inputs = standardInPaths } - val inputOutputMap = - if (options.output.isNotEmpty()) { - inputs.zip(options.output) { a, b -> - Pair(File(a), File(b)) - } - } else { - inputs.zip(inputs) { a, b -> - - } - }.toMap() - + val inputOutputMap = pairOutputs() val files = inputOutputMap.count { (input, _) -> input.isFile } val containsDirectory = inputOutputMap.any { (input, _) -> input.isDirectory } printFileNames = options.printStats && (files > 1 || containsDirectory) @@ -71,67 +66,21 @@ class Vgo( return handleFiles(inputOutputMap, writerOptions) } - private fun pairOutputs(): Map { - val inputFiles = options.input.map(::File) + private fun pairOutputs(): Map { return if (options.output.isNotEmpty()) { - inputFiles.zip(options.output.map(::File)).toMap() + options.input.zip(options.output) { a, b -> + Pair(File(a), Paths.get(b)) + } } else { - inputFiles.mapIndexed { index, input -> - if (!input.isDirectory) { - val outputExtension = when (options.format) { - "svg" -> "svg" - "vd" -> "xml" - else -> input.extension - } - val outputFilePath = options.output.dropLastWhile { it != '.' } + outputExtension - } - }.toMap() - } - } - - private fun handleFiles( - inputOutputMap: Map, - writerOptions: Set, - ): Int { - for (entry in inputOutputMap) { - val (input, output) = entry - - when { - entry.isFilePair -> handleFile(input, output, writerOptions) - entry.isDirectoryPair -> handleDirectory(input, output, writerOptions) - !entry.inputExists -> { - System.err.println("${input.path} does not exist.") - return 65 - } - else -> { - System.err.println( - """ - A given input and output pair (grouped positionally) - must be either files or directories. - Input is a ${if (input.isFile) "file" else "directory"} - path: ${input.absolutePath} - exists: ${input.exists()} - isWritable: ${input.canWrite()} - Output is a ${if (output.isFile) "file" else "directory"} - path: ${output.absolutePath} - exists: ${input.exists()} - isWritable: ${input.canWrite()} - - Storage: ${output.usableSpace} / ${output.totalSpace} is usable. - """.trimIndent(), - ) - - return 65 - } + options.input.zip(options.input) { a, b -> + Pair(File(a), Paths.get(b)) } - } - - return 0 + }.toMap() } private fun handleFile( input: File, - output: File, + outputPath: Path, options: Set, ) { input.inputStream().use { inputStream -> @@ -186,7 +135,7 @@ class Vgo( com.jzbrooks.vgo.vd .parse(rootNodes.first()) } - else -> if (input == output) return else null + else -> if (outputPath.isSameFileAs(input.toPath())) return else null } if (graphic is VectorDrawable && this.options.format == "svg") { @@ -204,6 +153,12 @@ class Vgo( optimizationRegistry?.apply(graphic) } + val output = when(this.options.format) { + "vd" -> outputPath.resolveSibling("${outputPath.fileName}.xml") + "svg" -> outputPath.resolveSibling("${outputPath.fileName}.svg") + else -> outputPath + }.toFile() + if (output.parentFile?.exists() == false) output.parentFile.mkdirs() if (!output.exists()) output.createNewFile() @@ -239,16 +194,57 @@ class Vgo( } } + private fun handleFiles( + inputOutputMap: Map, + writerOptions: Set, + ): Int { + for (entry in inputOutputMap) { + val (input, output) = entry + + when { + entry.isFilePair -> handleFile(input, output, writerOptions) + entry.isDirectoryPair -> handleDirectory(input, output, writerOptions) + !entry.inputExists -> { + System.err.println("${input.path} does not exist.") + return 65 + } + else -> { + val output = output.toFile() + System.err.println( + """ + A given input and output pair (grouped positionally) + must be either files or directories. + Input is a ${if (input.isFile) "file" else "directory"} + path: ${input.absolutePath} + exists: ${input.exists()} + isWritable: ${input.canWrite()} + Output is a ${if (output.isFile) "file" else "directory"} + path: ${output.absolutePath} + exists: ${input.exists()} + isWritable: ${input.canWrite()} + + Storage: ${output.usableSpace} / ${output.totalSpace} is usable. + """.trimIndent(), + ) + + return 65 + } + } + } + + return 0 + } + private fun handleDirectory( input: File, - output: File, + output: Path, options: Set, ) { assert(input.isDirectory) - assert(output.isDirectory || !output.exists()) + assert(output.isDirectory() || !output.exists()) for (file in input.walkTopDown().filter { file -> !file.isHidden && !file.isDirectory }) { - handleFile(file, File(output, file.name), options) + handleFile(file, output.resolve(file.name), options) } if (this.options.printStats) { @@ -282,14 +278,14 @@ class Vgo( else -> "$bytes B" } - private val Map.Entry.inputExists + private val Map.Entry.inputExists get() = key.exists() - private val Map.Entry.isFilePair - get() = key.isFile && (value.isFile || !value.exists()) + private val Map.Entry.isFilePair + get() = key.isFile && (value.isRegularFile() || !value.exists()) - private val Map.Entry.isDirectoryPair - get() = key.isDirectory && (value.isDirectory || !value.exists()) + private val Map.Entry.isDirectoryPair + get() = key.isDirectory && (value.isDirectory() || !value.exists()) data class Options( val printVersion: Boolean = false,