Last active
December 15, 2023 23:11
-
-
Save fokot/9ede8986562e90d566adefc5d44260b7 to your computer and use it in GitHub Desktop.
dependency tree to jstree
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.{BufferedWriter, OutputStreamWriter} | |
import java.nio.file.{Files, Paths, StandardOpenOption} | |
import StandardOpenOption._ | |
import scala.io.Source | |
import scala.util.Using | |
/** | |
* Generates a dependency tree in html format. | |
* `dependencyBrowseTree` fails on SO in our big project but `dependencyTree` works. | |
* | |
* Use it like: | |
* | |
* sbt dependencyTree | scala-cli DependencyJsTree.scala > dep.html | |
* | |
* Or you can also uncomment files version | |
*/ | |
object DependencyJsTree { | |
def main(args: Array[String]): Unit = { | |
val root = args match { | |
case Array(r) => r | |
case _ => "com.cloudfarms:cloudfarms_2.13:1.3.0" | |
} | |
// val source = Source.fromFile("dep.txt") | |
val source = Source.stdin | |
// val target = Files.newBufferedWriter(Paths.get("dep.html"), CREATE, TRUNCATE_EXISTING) | |
val target = new BufferedWriter(new OutputStreamWriter(System.out)) | |
generateHtml(root, source, target) | |
} | |
val pageStart = | |
"""<!doctype html> | |
|<html> | |
|<head | |
| <meta charset="utf-8"> | |
| <title>dependencyBrowseTree</title> | |
| | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script> | |
| <script src="tree.data.js"></script> | |
| | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css"/> | |
| | |
| <style> | |
| #input-field { | |
| display: inline; | |
| } | |
| #tree_div { | |
| font-family: monospace | |
| } | |
| </style> | |
|</head> | |
|<body> | |
|<h1>Dependencies</h1> | |
|Search: <input type="search" id="input-field" value=""> | |
|<div id="tree_div" class="jstree-no-icons"></div> | |
| | |
|<script> | |
|const tree_data = | |
""".stripMargin | |
val pageEnd = | |
"""$(function() { | |
| $('#tree_div').jstree({ | |
| "plugins": ["search", "sort"], | |
| "core": { | |
| "data": tree_data | |
| } | |
| }); | |
| var to = false; | |
| $('#input-field').keyup(function() { | |
| if (to) { | |
| clearTimeout(to); | |
| } | |
| to = setTimeout(function() { | |
| var v = $('#input-field').val(); | |
| $('#tree_div').jstree(true).search(v); | |
| }, 250); | |
| }); | |
|}); | |
|</script> | |
|</body> | |
|</html> | |
|""".stripMargin | |
def generateHtml(root: String, source: Source, writer: BufferedWriter): Unit = | |
Using.resources( | |
source, | |
writer | |
) { (source, target) => | |
target.write(pageStart) | |
target.write(s"""{ "text": "${root}", "children": [""") | |
val lastLevel = source.getLines().dropWhile(!_.contains(root)).drop(1).takeWhile(_.contains("[info]")).foldLeft(0)(process(target)) | |
(0 to lastLevel).reverse.foreach { i => | |
target.write(" " * i) | |
if (i == 0) | |
target.write("]}\n") | |
else | |
target.write("]},\n") | |
} | |
target.write(pageEnd) | |
} | |
def process(target: BufferedWriter)(previousLevel: Int, lineFull: String): Int = { | |
val line = lineFull.replace("[info]", "").trim | |
if (line.contains("+-")) { | |
val (levelString, name) = line.splitAt(line.indexOf("+-") + 2) | |
val level = levelString.count(_ == '|') + 1 | |
if(level < previousLevel) { | |
(level to previousLevel).reverse.foreach { i => | |
target.write(" " * i) | |
target.write("]},\n") | |
} | |
target.write(" " * level) | |
target.write(s"""{ "text": "$name", "children": [""") | |
} else if (level == previousLevel) { | |
target.write("]},\n") | |
target.write(" " * level) | |
target.write(s"""{ "text": "$name", "children": [""") | |
} else { | |
target.write("\n") | |
target.write(" " * level) | |
target.write(s"""{ "text": "$name", "children": [""") | |
} | |
level | |
} else | |
previousLevel | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//> using scala "2.13.12" | |
//> using lib "dev.zio::zio:2.0.20" | |
//> using lib "dev.zio::zio-streams:2.0.20" | |
import zio.Console.{printLine, print} | |
import zio.{Chunk, Scope, ZIO, ZIOAppArgs, ZIOAppDefault} | |
import zio.stream.{ZPipeline, ZSink, ZStream} | |
import java.io.BufferedWriter | |
import java.nio.file.Paths | |
import scala.io.Source | |
import scala.util.Using | |
/** | |
* Generates a dependency tree in html format. | |
* `dependencyBrowseTree` fails on SO in our big project but `dependencyTree` works. | |
* | |
* Use it like: | |
* | |
* sbt dependencyTree | scala-cli DependencyJsTreeStreams.scala > dep.html | |
* | |
* Or you can also uncomment files version | |
*/ | |
object DependencyJsTreeStreams extends ZIOAppDefault { | |
// val source = ZIO.attempt(Source.fromFile("dep.txt")) | |
val source = ZIO.succeed(Source.stdin) | |
// val target = ZPipeline.utf8Encode >>> ZSink.fromPath(Paths.get("dep.html")) | |
val target = ZSink.foreach((s: String) => printLine(s)) | |
def run: ZIO[ZIOAppArgs with Scope, Any, Any] = | |
getArgs.map { | |
case Chunk(r) => r | |
case _ => "com.cloudfarms:cloudfarms_2.13:1.3.0" | |
}.flatMap { root => | |
val linesAndLevelsDependecies = ZStream.scoped(ZIO.fromAutoCloseable(source)) | |
.flatMap(source => ZStream.fromIterator(source.getLines())) | |
.dropUntil(_.contains(root)) | |
.filter(_.contains("+-")) | |
.map(levelAndName) | |
val linesAndLevels = ZStream.succeed((0, root)) ++ linesAndLevelsDependecies ++ ZStream.succeed((0, "")) | |
val dependenciesJson = linesAndLevels.sliding(2) | |
.flatMap(a => lineToStream(a(0)._1, a(1)._1, a(0)._2)) | |
.intersperse("\n") | |
val result = ZStream.succeed(pageStart) ++ dependenciesJson ++ ZStream.succeed("\n") ++ ZStream.succeed(pageEnd) | |
result.run(target) | |
} | |
def levelAndName(line: String): (Int, String) = { | |
val (levelString, name) = line.splitAt(line.indexOf("+-") + 2) | |
val level = levelString.count(_ == '|') + 1 | |
(level, name) | |
} | |
def lineToStream(currentLevel: Int, nextLevel: Int, text: String): ZStream[Any, Nothing, String] = | |
if (currentLevel < nextLevel) | |
ZStream.succeed(" " * currentLevel ++ s"""{ "text": "$text", "children": [""") | |
else if (currentLevel == nextLevel) | |
ZStream.succeed(" " * currentLevel ++ s"""{ "text": "$text", "children": [] },""") | |
else | |
ZStream.succeed(" " * currentLevel ++ s"""{ "text": "$text", "children": [] }""") ++ | |
ZStream.fromIterable((nextLevel until currentLevel).reverse.map(i => " " * i + "]}" ++ (if (i == 0) "" else ","))) | |
val pageStart = | |
"""<!doctype html> | |
|<html> | |
|<head | |
| <meta charset="utf-8"> | |
| <title>dependencyBrowseTree</title> | |
| | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script> | |
| <script src="tree.data.js"></script> | |
| | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css"/> | |
| | |
| <style> | |
| #input-field { | |
| display: inline; | |
| } | |
| #tree_div { | |
| font-family: monospace | |
| } | |
| </style> | |
|</head> | |
|<body> | |
|<h1>Dependencies</h1> | |
|Search: <input type="search" id="input-field" value=""> | |
|<div id="tree_div" class="jstree-no-icons"></div> | |
| | |
|<script> | |
|const tree_data = | |
""".stripMargin | |
val pageEnd = | |
"""$(function() { | |
| $('#tree_div').jstree({ | |
| "plugins": ["search", "sort"], | |
| "core": { | |
| "data": tree_data | |
| } | |
| }); | |
| var to = false; | |
| $('#input-field').keyup(function() { | |
| if (to) { | |
| clearTimeout(to); | |
| } | |
| to = setTimeout(function() { | |
| var v = $('#input-field').val(); | |
| $('#tree_div').jstree(true).search(v); | |
| }, 250); | |
| }); | |
|}); | |
|</script> | |
|</body> | |
|</html> | |
|""".stripMargin | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment