aboutsummaryrefslogtreecommitdiff
path: root/tools/gui/src/Main.scala
blob: 3b4bd909938b1dae366358fd55e163fb935f8067 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import java.io.{File, IOException}
import java.net.MalformedURLException
import java.nio.file.Files

import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer

import scala.io.Source
import scala.util.{Failure, Success, Try}
import scalaj.http.Http

object Main {

  private val maven_host = "search.maven.org"
  private val cbt_home = System.getenv("CBT_HOME")

  implicit class StringExtensionMethods(str: String) {
    def /(s: String): String = str + File.separator + s
  }

  val uiPort = 9080

  def main(args: Array[String]) = launchUi(new File(args(0)), args(1))

  def launchUi(projectDirectory: File, scalaMajorVersion: String): Unit = {
    val staticBase = new File(cbt_home / "tools" / "gui" / "resources" / "web").toURI.toURL.toExternalForm
    val server = new JettyServer(uiPort, staticBase) {
      override def route(method: String,
                         path: String,
                         param: String => String,
                         setContentType: String => Unit) = (method, path) match {
        case ("GET", "/cwd") =>
          Success(s"""["$projectDirectory"]""")
        case ("POST", "/project/new") =>
          val name = param("name")
          val defaultPackage = param("pack")
          val dependencies = param("dependencies")
          val flags = param("flags")
          handleIoException {
            new ProjectBuilder(name, defaultPackage, dependencies, flags, projectDirectory, scalaMajorVersion).build()
            Success("[]")
          }
        case ("POST", "/project/copy") =>
          val name = param("name")
          val source = new File(cbt_home / "examples" / name)
          val target = new File(projectDirectory.getAbsolutePath / name)
          handleIoException {
            copyTree(source, target)
            Success("[]")
          }
        case ("GET", "/dependency") =>
          val query = param("query")
          handleIoException(handleMavenBadResponse(searchDependency(query)))
        case ("GET", "/dependency/version") =>
          val group = param("group")
          val artifact = param("artifact")
          handleIoException(handleMavenBadResponse(searchDependencyVersion(group, artifact)))
        case ("GET", "/examples") =>
          handleIoException {
            val names = new File(cbt_home / "examples").listFiles().filter(_.isDirectory).sortBy(_.getName)
                .map('"' + _.getName + '"').mkString(",")
            Success(s"[$names]")
          }
        case ("GET", "/example/files") =>
          val name = param("name")
          handleIoException {
            val dir = new File(cbt_home / "examples" / name)
            if (dir.exists())
              Success(serializeTree(dir))
            else
              Failure(new IllegalArgumentException(s"Incorrect example name: $name"))
          }
        case ("GET", "/example/file") =>
          setContentType("text/plain")
          val path = param("path")
          handleIoException {
            val file = new File(path)
            Success {
              val content = Source.fromFile(file).mkString
              if (file.getName.endsWith(".md"))
                parseMd(content)
              else
                content
            }
          }
        case _ =>
          Failure(new MalformedURLException(s"Incorrect path: $path"))
      }
    }
    server.start()
    if(!java.awt.GraphicsEnvironment.isHeadless()) {
      java.awt.Desktop.getDesktop.browse(new java.net.URI(s"http://localhost:$uiPort/"))
    }

    println("Press Enter to stop UI server.")
    while (Source.stdin.getLines().next().nonEmpty) {}
    server.stop()
  }

  private def searchDependency(query: String) = {
    Http(s"http://$maven_host/solrsearch/select")
        .param("q", query)
        .param("rows", "30")
        .param("wt", "json")
        .asString.body
  }

  private def searchDependencyVersion(group: String, artifact: String) = {
    val query = s"""q=g:"$group"+AND+a:"$artifact""""
    Http(s"http://$maven_host/solrsearch/select?" + query)
        .param("rows", "30")
        .param("wt", "json")
        .param("core", "gav")
        .asString.body
  }

  private def handleIoException(f: => Try[String]) = try f catch {
    case e: IOException =>
      e.printStackTrace()
      Failure(e)
  }

  private def handleMavenBadResponse(result: String) = {
    if (result.startsWith("{"))
      Success(result)
    else
      Failure(new Exception(s"Bad response from $maven_host: $result"))
  }

  private def serializeTree(file: File): String = {
    val data = if (file.isDirectory)
      s""","children":[${file.listFiles().sortBy(_.getName).map(serializeTree).mkString(",")}]"""
    else
      ""
    s"""{"name":"${file.getName}","path":"${file.getAbsolutePath}"$data}"""
  }

  private def parseMd(s: String) = {
    val parser = Parser.builder().build()
    val document = parser.parse(s)
    val renderer = HtmlRenderer.builder().build()
    renderer.render(document)
  }

  private def copyTree(sourceRoot: File, targetRoot: File) =
    listFilesRecursive(sourceRoot).sorted.foreach { source =>
      val path = source.getAbsolutePath.replace(sourceRoot.getAbsolutePath, targetRoot.getAbsolutePath)
      val file = new File(path)
      if (source.isDirectory)
        file.mkdirs()
      else
        Files.copy(source.toPath, file.toPath)
    }

  private def listFilesRecursive(f: File): Seq[File] =
    f +: (if (f.isDirectory) f.listFiles.flatMap(listFilesRecursive).toVector else Vector[File]())

}