From f85414c97698f0ae7aac392a31020fb558b96a6a Mon Sep 17 00:00:00 2001 From: Carmi Grushko Date: Tue, 1 Feb 2022 01:22:30 -0800 Subject: [PATCH] When formatting stdin, print formatted code to stdout regardless of whether it changed Reviewed By: strulovich Differential Revision: D33888492 fbshipit-source-id: 00602c756c932b10594a19d7ae2b43c6d0639f41 --- .../main/java/com/facebook/ktfmt/cli/Main.kt | 64 ++++++++++++------- .../java/com/facebook/ktfmt/cli/MainTest.kt | 26 +++++++- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/core/src/main/java/com/facebook/ktfmt/cli/Main.kt b/core/src/main/java/com/facebook/ktfmt/cli/Main.kt index d2e7b9e5..7fd80eb0 100644 --- a/core/src/main/java/com/facebook/ktfmt/cli/Main.kt +++ b/core/src/main/java/com/facebook/ktfmt/cli/Main.kt @@ -25,7 +25,7 @@ import java.io.IOException import java.io.InputStream import java.io.InputStreamReader import java.io.PrintStream -import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicInteger import kotlin.system.exitProcess class Main( @@ -70,13 +70,17 @@ class Main( fun run(): Int { if (parsedArgs.fileNames.isEmpty()) { err.println( - "Usage: ktfmt [--dropbox-style | --google-style | --kotlinlang-style] File1.kt File2.kt ...") + "Usage: ktfmt [--dropbox-style | --google-style | --kotlinlang-style] [--dry-run] [--set-exit-if-changed] File1.kt File2.kt ...") return 1 } if (parsedArgs.fileNames.size == 1 && parsedArgs.fileNames[0] == "-") { - val success = format(null) - return if (success) 0 else 1 + return try { + val alreadyFormatted = format(null) + if (!alreadyFormatted && parsedArgs.setExitIfChanged) 1 else 0 + } catch (e: Exception) { + 1 + } } val files: List @@ -92,9 +96,17 @@ class Main( return 1 } - val success = AtomicBoolean(true) - files.parallelStream().forEach { success.compareAndSet(true, format(it)) } - return if (success.get()) 0 else 1 + val retval = AtomicInteger(0) + files.parallelStream().forEach { + try { + if (!format(it) && parsedArgs.setExitIfChanged) { + retval.set(1) + } + } catch (e: Exception) { + retval.set(1) + } + } + return retval.get() } /** @@ -104,46 +116,50 @@ class Main( * to [out]. Otherwise, this will run the appropriate formatting as normal. * * @param file The file to format. If null, the code is read from . - * @return True if changes were made or no changes were needed, false if there was a failure or if - * changes were made and the --set-exit-if-changed flag is set. + * @return true iff input is valid and already formatted. */ private fun format(file: File?): Boolean { val fileName = file?.toString() ?: "" try { val code = file?.readText() ?: BufferedReader(InputStreamReader(input)).readText() - val formattedCode = Formatter.format(parsedArgs.formattingOptions, code) - - if (code == formattedCode) { - // The code was already formatted, nothing more to do here - err.println("No changes: $fileName") - return true + val alreadyFormatted = code == formattedCode + + // stdin + if (file == null) { + if (parsedArgs.dryRun) { + if (!alreadyFormatted) { + out.println("") + } + } else { + out.print(formattedCode) + } + return alreadyFormatted } if (parsedArgs.dryRun) { - out.println(fileName) - } else { - if (file != null) { - file.writeText(formattedCode) - } else { - out.print(formattedCode) + if (!alreadyFormatted) { + out.println(fileName) } + } else { + file.writeText(formattedCode) err.println("Done formatting $fileName") } - // If setExitIfChanged is true, then any change should result in an exit code of 1. - return if (parsedArgs.setExitIfChanged) false else true + return alreadyFormatted } catch (e: IOException) { err.println("Error formatting $fileName: ${e.message}; skipping.") + throw e } catch (e: ParseError) { handleParseError(fileName, e) + throw e } catch (e: FormattingError) { for (diagnostic in e.diagnostics()) { System.err.println("$fileName:$diagnostic") } e.printStackTrace(err) + throw e } - return false } private fun handleParseError(fileName: String, e: ParseError) { diff --git a/core/src/test/java/com/facebook/ktfmt/cli/MainTest.kt b/core/src/test/java/com/facebook/ktfmt/cli/MainTest.kt index 9f19af2f..03660aeb 100644 --- a/core/src/test/java/com/facebook/ktfmt/cli/MainTest.kt +++ b/core/src/test/java/com/facebook/ktfmt/cli/MainTest.kt @@ -106,8 +106,7 @@ class MainTest { val code = "fun f1 ( ) : Int = 0" Main(code.byteInputStream(), PrintStream(out), PrintStream(err), arrayOf("-")).run() - val expected = """fun f1(): Int = 0 - |""".trimMargin() + val expected = "fun f1(): Int = 0\n" assertThat(out.toString("UTF-8")).isEqualTo(expected) } @@ -234,6 +233,29 @@ class MainTest { .containsExactly(f1, f2, f5, f6, f7) } + @Test + fun `formatting from stdin prints formatted code to stdout regardless of whether it was already formatted`() { + val expected = """fun f() = println("hello, world")""" + "\n" + + Main( + """fun f ( ) = println("hello, world")""".byteInputStream(), + PrintStream(out), + PrintStream(err), + arrayOf("-")) + .run() + assertThat(out.toString("UTF-8")).isEqualTo(expected) + + out.reset() + + Main( + """fun f () = println("hello, world")""".byteInputStream(), + PrintStream(out), + PrintStream(err), + arrayOf("-")) + .run() + assertThat(out.toString("UTF-8")).isEqualTo(expected) + } + @Test fun `--dry-run prints filename and does not change file`() { val code = """fun f () = println( "hello, world" )"""