Commits

Vetle Leinonen-Roeim committed 38584d7

Changing this project to a command line client

  • Participants
  • Parent commits baed67a

Comments (0)

Files changed (9)

 target
 project/boot
 .idea*
+.ensime
+
+syntax: regex
+*~
+*.swp
+
+

build.sbt

-name := "sshlog"
-
-version := "1.0"
-
-scalaVersion := "2.9.0"
-
-// mainClass := Some("SSHLog")
-
-seq(webSettings :_*)
-
-libraryDependencies ++= Seq(
-        "org.eclipse.jetty" % "jetty-webapp" % "7.3.0.v20110203" % "jetty",
-        "ch.qos.logback" % "logback-classic" % "0.9.26",
-        "javax.servlet" % "servlet-api" % "2.5" % "provided->default"
-)
-
-libraryDependencies += "org.fusesource.scalate" % "scalate-core" % "1.5.0"

project/Build.scala

+import sbt._
+import Keys._
+
+object Build extends Build
+{
+  lazy val root = Project("stail", file(".")) settings(sbtassembly.Plugin.assemblySettings: _*)
+
+  override lazy val settings = super.settings ++ Seq(
+    name := "stail",
+    libraryDependencies ++= Seq("org.scala-lang" % "scala-compiler" % "2.9.1",
+				"jline" % "jline" % "0.9.9"),
+    scalaVersion := "2.9.1"
+  )
+
+}

project/plugins/build.sbt

-resolvers += "Web plugin repo" at "http://siasia.github.com/maven2"
-
-// Following means libraryDependencies += "com.github.siasia" %% "xsbt-web-plugin" % <sbt version>
-libraryDependencies <+= sbtVersion("com.github.siasia" %% "xsbt-web-plugin" % _)
-
-resolvers += "sbt-idea-repo" at "http://mpeltonen.github.com/maven/"
-
-libraryDependencies += "com.github.mpeltonen" %% "sbt-idea" % "0.10.0"
+libraryDependencies <+= (sbtVersion) { sv => "com.eed3si9n" %% "sbt-assembly" % ("sbt" + sv + "_0.6") }

src/main/resources/index.scaml

-<!doctype HTML>
-%html
-    %head
-        %link{:rel => "stylesheet",
-              :type => "text/css",
-              :href => "/sshlog.css"}
-    %body
-        %header
-            %h1 SSHLog
-        %div{:class => "menu"}
-            %ul
-                %li Add logfile
-            %ul

src/main/scala/SSHLogServlet.scala

-/**
- * Created by IntelliJ IDEA.
- * User: vetler
- * Date: 8/2/11
- * Time: 9:06 PM
- * To change this template use File | Settings | File Templates.
- */
-
-import javax.servlet.http.{HttpServlet,
-HttpServletRequest => HSReq, HttpServletResponse => HSResp}
-import org.fusesource.scalate._
-
-class SSHLogServlet extends HttpServlet {
-
-  override def doGet(req: HSReq, resp: HSResp) {
-    val engine = new TemplateEngine
-    val output = engine.layout("index.scaml")
-    resp.getWriter.print(output)
-  }
-
-}

src/main/scala/sshlog.scala

-import java.io.File
-import scala.io.Source
-import com.jcraft.jsch._
-
-object SSHLog {
-  val defaultForwardingPort = 10000
-  val defaultTimeout = 10000
-
-  def usage() {
-    println("""
-Usage: sshlog <FILE>
-""")
-
-    exit(1)
-  }
-
-  def main(args: Array[String]) {
-    if (args.length == 0) usage
-
-    val forwardingPort = if (args.length == 3) args(2).toInt else defaultForwardingPort
-    
-    var configurations = List[Configuration]()
-    val configurationFile = new File(args(0))
-    Source.fromFile(configurationFile)("UTF-8").getLines() foreach { untrimmedLine =>
-      val line = untrimmedLine.trim
-      if (line matches "\\[.*\\]") {
-        val id = line substring (line.indexOf("[") + 1, line.indexOf("]"))
-        configurations = configurations ::: List(new Configuration(id))
-      }
-
-      if (line matches "file\\s*=\\s*.*") {
-        val filename = line.substring(line.indexOf("=") + 1).trim
-        configurations.last.addFile(filename)
-      }
-
-      if (line matches "server\\s*=\\s*.*") {
-        val server = line.substring(line.indexOf("=") + 1).trim
-        configurations.last.setServer(server)
-      }
-
-      if (line matches "user\\s*=\\s*.*") {
-        val user = line.substring(line.indexOf("=") + 1).trim
-        configurations.last.user = user
-      }
-
-      if (line matches "password\\s*=\\s*.*") {
-        val password = line.substring(line.indexOf("=") + 1).trim
-        configurations.last.password = password
-      }
-
-      if (line matches "forward-through\\s*=\\s*.*") {
-        val forwardThroughServer = line.substring(line.indexOf("=") + 1).trim
-        configurations.last.setForwarding(forwardThroughServer)
-      }
-
-    }
-
-    if (configurations.size == 0) {
-      println("No configurations found in " + args(0))
-      exit(1)
-    } else {
-      for (config <- configurations if config.id == args(1)) {
-        config.forwardThroughServer match {
-          case Some(forwardedThroughServer) => {
-            println("Tailing log files on " + config.server + ", forwarded through " + forwardedThroughServer)
-            val jsch = new JSch()
-            val forwardingSession = createSession(jsch, forwardedThroughServer, config.user, config.password, 22)
-            forwardingSession.connect(defaultTimeout)
-            forwardingSession.setPortForwardingL(forwardingPort, config.server, 22)
-
-            val session = createSession(jsch, "localhost", config.user, config.password, forwardingPort)
-            session.connect(defaultTimeout)
-
-            val channel = session.openChannel("exec").asInstanceOf[ChannelExec]
-            channel.setCommand("tail -f " + config.files.mkString("", " ", ""))
-            channel.setInputStream(null)
-            channel.setErrStream(System.err)
-            channel.setOutputStream(System.out)
-            channel.connect(defaultTimeout)
-          }
-          case None => {
-            println("Tailing log files on " + config.server)
-            val jsch = new JSch()
-            val session = createSession(jsch, config.server, config.user, config.password, 22)
-            session.connect(defaultTimeout)
-
-            val channel = session.openChannel("exec").asInstanceOf[ChannelExec]
-            channel.setCommand("tail -f " + config.files.mkString("", " ", ""))
-            channel.setInputStream(null)
-            channel.setErrStream(System.err)
-            channel.setOutputStream(System.out)
-            channel.connect(defaultTimeout)
-          }
-        }
-      }
-    }
-  }
-
-  def createSession(jsch: JSch, server: String, user: String, password: String, port: Int): Session = {
-    val session = jsch.getSession(user, server, port)
-    setConfiguration(session)
-    session.setUserInfo(new SimpleUserInfo(password))
-    session
-  }
-
-  def setConfiguration(session: Session) {
-    val properties = new java.util.Properties
-    properties.put("StrictHostKeyChecking", "no") // Turn off strict host key checking
-    session.setConfig(properties)
-  }
-
-}
-
-class SimpleUserInfo(password: String) extends UserInfo {
-  override def getPassword(): String = password
-  override def promptYesNo(str: String) = true
-  override def showMessage(message: String) { println(message) }
-  override def getPassphrase(): String = null
-  override def promptPassphrase(str: String) = true
-  override def promptPassword(str: String) = true
-}
-
-class Configuration(id: String) {
-  var files = List[String]()
-  var server = ""
-  var user = "root"
-  var password = ""
-  var forwardThroughServer: Option[String] = None
-
-  def id(): String = id
-
-  def setForwarding(server: String) {
-    forwardThroughServer = Some(server)
-  }
-
-  def setServer(server: String) {
-    this.server = server
-  }
-
-  def addFile(filename: String) {
-    files = files ::: List(filename)
-  }
-
-  override def toString(): String = {
-    "[" + id + "]" + files.mkString("", ",", "")
-  }
-}

src/main/scala/stail.scala

+// Good, old java imports
+import java.io.File
+import java.io.Console
+
+// Look ma, Scala!
+import scala.io.Source
+import scala.tools.nsc.interpreter.ILoop.break
+import scala.tools.nsc.interpreter.NamedParam
+
+// Java library for SSH
+import com.jcraft.jsch._
+
+object STail {
+  val defaultTimeout = 10000
+
+  def usage() {
+    println("""
+Usage: stail <OPTIONS> username@host:/path/to/file
+
+Options:
+    -via HOSTSPEC     Tail file on remote host by using SSH forwarding through the specified host.
+                      Local port to be used for port forwarding can also be specified.
+
+                      Example: user@example.com:1001:/path/to/file
+""")
+
+    exit(1)
+  }
+
+  def main(args: Array[String]) {
+    args.length match {
+      case 1 => Nil
+      case 3 => setUpForwarding(args)
+      case _ => usage
+    }
+
+    val (username, host, port, path) = args.length match {
+      case 1 => readHostSpec(args(0))
+      case 3 => readHostSpec(args(2))
+      case _ => dieWithError("Unrecognized number of arguments: "+ args.length)
+    }
+
+//         config.forwardThroughServer match {
+//           case Some(forwardedThroughServer) => {
+//             println("Tailing log files on " + config.server + ", forwarded through " + forwardedThroughServer)
+//             val jsch = new JSch()
+//             val forwardingSession = createSession(jsch, forwardedThroughServer, config.user, config.password, 22)
+//             forwardingSession.connect(defaultTimeout)
+//             forwardingSession.setPortForwardingL(forwardingPort, config.server, 22)
+
+//             val session = createSession(jsch, "localhost", config.user, config.password, forwardingPort)
+//             session.connect(defaultTimeout)
+
+//             val channel = session.openChannel("exec").asInstanceOf[ChannelExec]
+//             channel.setCommand("tail -f " + config.files.mkString("", " ", ""))
+//             channel.setInputStream(null)
+//             channel.setErrStream(System.err)
+//             channel.setOutputStream(System.out)
+//             channel.connect(defaultTimeout)
+//           }
+
+    val password = readPassword().toString
+
+    println("Tailing log files on " + host)
+    val jsch = new JSch()
+    val session = createSession(jsch, host, username, password, 22)
+    session.connect(defaultTimeout)
+    
+    val channel = session.openChannel("exec").asInstanceOf[ChannelExec]
+    channel.setCommand("tail -f "+ path)
+    channel.setInputStream(null)
+    channel.setErrStream(System.err)
+    channel.setOutputStream(System.out)
+    channel.connect(defaultTimeout)
+  }
+
+  def readPassword() = {
+    print("Password: ")
+    new jline.ConsoleReader().readLine('*')
+  }
+  
+  def dieWithError(error: String): (String, String, Option[String], String) = {
+    println(error)
+    exit(1)
+  }
+
+  object Username {
+    def unapply(f: String) = {
+      f.substring(0, f.indexOf('@'))
+    }
+  }
+
+  object Host {
+    def unapply(f: String) = {
+      //break(List(NamedParam("f", f)))
+      f.substring(f.indexOf('@') + 1, f.indexOf(':'))
+    }
+  }
+
+  object Port {
+    def unapply(f: String): Option[String] = {
+      var idx = f.indexOf(':')
+      var nextIdx = f.indexOf(':', idx+1)
+      if (nextIdx == -1 || idx == nextIdx)
+	None
+      else
+	Some(f.substring(idx+1, nextIdx))
+    }
+  }
+
+  object Path {
+    def unapply(f: String) = {
+      f.substring(f.lastIndexOf(':') + 1)
+    }
+  }
+
+  def readHostSpec(hostSpec: String): (String, String, Option[String], String) = {
+    // username@host(:port):/path/to/file
+    val username = Username.unapply(hostSpec)
+    val host = Host.unapply(hostSpec)
+    val port = Port.unapply(hostSpec)
+    val path = Path.unapply(hostSpec)
+
+    (username, host, port, path)
+  }
+
+
+  def createSession(jsch: JSch, server: String, user: String, password: String, port: Int): Session = {
+    val session = jsch.getSession(user, server, port)
+    setConfiguration(session)
+    session.setUserInfo(new SimpleUserInfo(password))
+    session
+  }
+
+  def setConfiguration(session: Session) {
+    val properties = new java.util.Properties
+    properties.put("StrictHostKeyChecking", "no") // Turn off strict host key checking
+    session.setConfig(properties)
+  }
+
+  def setUpForwarding(args: Array[String]) {}
+}
+
+class SimpleUserInfo(password: String) extends UserInfo {
+  override def getPassword(): String = password
+  override def promptYesNo(str: String) = true
+  override def showMessage(message: String) { println(message) }
+  override def getPassphrase(): String = null
+  override def promptPassphrase(str: String) = true
+  override def promptPassword(str: String) = true
+}
+

src/main/webapp/WEB-INF/web.xml

-<!DOCTYPE web-app 
-    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
-    "http://java.sun.com/dtd/web-app_2_3.dtd">
-<web-app>
-  <servlet>
-    <servlet-name>sshlog</servlet-name>
-    <servlet-class>SSHLogServlet</servlet-class>
-  </servlet>
-  <servlet-mapping>
-    <servlet-name>sshlog</servlet-name>
-    <url-pattern>/</url-pattern>
-  </servlet-mapping>
-</web-app>