diff --git a/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala b/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala index 4661f5fdb..68ebf7fd8 100644 --- a/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala +++ b/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala @@ -36,6 +36,7 @@ private[sbt] object DependencyTreeSettings: case Quiet case Format(format: Fmt) case Out(out: String) + case Append case Browse enum Fmt: @@ -67,6 +68,7 @@ private[sbt] object DependencyTreeSettings: lazy val ArgOptionParser: Parser[Arg] = Space ~> (("--quiet" ^^^ Arg.Quiet) + | ("--append" ^^^ Arg.Append) | ("--browse" ^^^ Arg.Browse) | ("--out" ~> Space ~> StringBasic) .map(Arg.Out(_)) @@ -97,6 +99,7 @@ SUBCOMMAND OPTIONS --quiet Returns the output as task value, replacing asString + --append Append to the output file when used with --out --out Writes the output to the specified file; The file extension will influence the default subcommand --browse Opens the browser when combined with graph or html subcommand @@ -164,6 +167,7 @@ OPTIONS val args = ArgsParser.parsed.toList val isHelp = args.contains(Arg.Help) val isQuiet = args.contains(Arg.Quiet) + val isAppend = args.contains(Arg.Append) val isBrowse = args.contains(Arg.Browse) if isHelp then Def.task { s.log.info(usageText); "" } else @@ -195,19 +199,19 @@ OPTIONS case Fmt.List => rendering.FlatList.render(_.id.idString)(graph) case Fmt.Stats => rendering.Statistics.renderModuleStatsList(graph) case _ => rendering.AsciiTree.asciiTree(graph, asciiGraphWidth.value) - handleOutput(output, outFileOpt, isQuiet, s.log) + handleOutput(output, outFileOpt, isQuiet, isAppend, s.log) } case Fmt.Json => Def.task { val graph = dependencyTreeModuleGraph0.value val output = TreeView.createJson(graph) - handleOutput(output, outFileOpt, isQuiet, s.log) + handleOutput(output, outFileOpt, isQuiet, isAppend, s.log) } case Fmt.Xml => Def.task { val graph = dependencyTreeModuleGraph0.value val output = rendering.GraphML.graphMLAsString(graph) - handleOutput(output, outFileOpt, isQuiet, s.log) + handleOutput(output, outFileOpt, isQuiet, isAppend, s.log) } case Fmt.Html => Def.task { @@ -227,7 +231,8 @@ OPTIONS rendering.DOT.HTMLLabelRendering.AngleBrackets, dependencyDotNodeColors.value ) - if format == Fmt.Graph then handleOutput(output, outFileOpt, isQuiet, s.log) + if format == Fmt.Graph then + handleOutput(output, outFileOpt, isQuiet, isAppend, s.log) else val outputFile = DagreHTML.createFile(output, targetDir) if isBrowse then openBrowser(outputFile.toURI) @@ -281,7 +286,7 @@ OPTIONS val output = format match case Fmt.Json => rendering.LicenseInfo.renderJson(graph) case _ => rendering.LicenseInfo.render(graph) - handleOutput(output, outFileOpt, isQuiet, s.log) + handleOutput(output, outFileOpt, isQuiet, appendToFile = false, s.log) } }).evaluated, ) @@ -306,11 +311,15 @@ OPTIONS content: String, outputFileOpt: Option[File], isQuiet: Boolean, + appendToFile: Boolean, log: Logger, ): String = outputFileOpt match case Some(output) => - IO.write(output, content, IO.utf8) + val toWrite = + if appendToFile && output.exists() && output.length() > 0 then "\n" + content + else content + IO.write(output, toWrite, IO.utf8, append = appendToFile) if !isQuiet then log.info(s"wrote dependencies to $output") output.toString case None => diff --git a/main/src/test/scala/sbt/plugins/DependencyTreeTest.scala b/main/src/test/scala/sbt/plugins/DependencyTreeTest.scala index cb34bb14f..8b1cc76e1 100644 --- a/main/src/test/scala/sbt/plugins/DependencyTreeTest.scala +++ b/main/src/test/scala/sbt/plugins/DependencyTreeTest.scala @@ -27,6 +27,7 @@ object DependencyTreeTest extends verify.BasicTestSuite: assert(parseArgs(List("help")) == List(Arg.Help)) assert(parseArgs(List("--help")) == List(Arg.Help)) assert(parseArgs(List("--quiet")) == List(Arg.Quiet)) + assert(parseArgs(List("--append")) == List(Arg.Append)) assert(parseArgs(List("tree")) == List(Arg.Format(Fmt.Tree))) assert(parseArgs(List("--out", "/tmp/deps.txt")) == List(Arg.Out("/tmp/deps.txt"))) assert(parseArgs(List("--browse")) == List(Arg.Browse)) diff --git a/sbt-app/src/sbt-test/dependency-graph/append-output/a/src/main/scala/A.scala b/sbt-app/src/sbt-test/dependency-graph/append-output/a/src/main/scala/A.scala new file mode 100644 index 000000000..03f023c42 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-graph/append-output/a/src/main/scala/A.scala @@ -0,0 +1,2 @@ +object A: + def a: Int = 1 diff --git a/sbt-app/src/sbt-test/dependency-graph/append-output/b/src/main/scala/B.scala b/sbt-app/src/sbt-test/dependency-graph/append-output/b/src/main/scala/B.scala new file mode 100644 index 000000000..dfd86b758 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-graph/append-output/b/src/main/scala/B.scala @@ -0,0 +1,2 @@ +object B: + def b: Int = 2 diff --git a/sbt-app/src/sbt-test/dependency-graph/append-output/build.sbt b/sbt-app/src/sbt-test/dependency-graph/append-output/build.sbt new file mode 100644 index 000000000..93d9ad7b9 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-graph/append-output/build.sbt @@ -0,0 +1,26 @@ +scalaVersion := "2.12.21" +organization := "org.example" +version := "0.1" + +lazy val root = (project in file(".")) + .aggregate(a, b) + .settings( + publish / skip := true, + ) + +lazy val a = (project in file("a")).settings( + name := "a", + libraryDependencies += "org.typelevel" %% "cats-core" % "2.10.0", +) + +lazy val b = (project in file("b")).settings( + name := "b", + libraryDependencies += "com.lihaoyi" %% "pprint" % "0.9.0", +) + +TaskKey[Unit]("check") := { + val f = new File("target/tree.txt") + val content = IO.read(f) + assert(content.contains("org.typelevel:cats-core_2.12:2.10.0"), s"Missing cats-core in output:\n$content") + assert(content.contains("com.lihaoyi:pprint_2.12:0.9.0"), s"Missing pprint in output:\n$content") +} diff --git a/sbt-app/src/sbt-test/dependency-graph/append-output/test b/sbt-app/src/sbt-test/dependency-graph/append-output/test new file mode 100644 index 000000000..da2735d60 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-graph/append-output/test @@ -0,0 +1,3 @@ +> a/dependencyTree --out target/tree.txt +> b/dependencyTree --out target/tree.txt --append +> check