Skip to content

Commit fcc916f

Browse files
committed
Adding --csv option to search and retrieve (Issue #4 )
1 parent dbb0901 commit fcc916f

File tree

8 files changed

+102
-14
lines changed

8 files changed

+102
-14
lines changed

build.sbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ libraryDependencies += "io.spray" %% "spray-json" % "1.3.3"
2727
libraryDependencies += "de.vandermeer" % "asciitable" % "0.3.2"
2828
libraryDependencies += "com.lihaoyi" %% "fansi" % "0.2.5"
2929
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value
30+
libraryDependencies += "au.com.bytecode" % "opencsv" % "2.4"
3031

3132
debianPackageDependencies := Seq("java8-runtime-headless")
3233

src/main/scala/de/upb/cs/swt/delphi/cli/Config.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ package de.upb.cs.swt.delphi.cli
2626
case class Config(server: String = sys.env.getOrElse("DELPHI_SERVER", "https://delphi.cs.uni-paderborn.de/api/"),
2727
verbose: Boolean = false,
2828
raw: Boolean = false,
29+
csv: String = "",
2930
silent: Boolean = false,
3031
list : Boolean = false,
3132
mode: String = "",
@@ -36,5 +37,6 @@ case class Config(server: String = sys.env.getOrElse("DELPHI_SERVER", "https://d
3637
opts: List[String] = List()) {
3738

3839
lazy val consoleOutput = new ConsoleOutput(this)
40+
lazy val csvOutput = new CsvOutput(this)
3941

4042
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (C) 2018 The Delphi Team.
2+
// See the LICENCE file distributed with this work for additional
3+
// information regarding copyright ownership.
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package de.upb.cs.swt.delphi.cli
18+
19+
import java.io.{BufferedWriter, FileWriter}
20+
21+
import de.upb.cs.swt.delphi.cli.artifacts.Result
22+
import au.com.bytecode.opencsv.CSVWriter
23+
import de.upb.cs.swt.delphi.cli.commands.SearchCommand.information
24+
import de.vandermeer.asciitable.{AsciiTable, CWC_LongestLine}
25+
import de.vandermeer.skb.interfaces.transformers.textformat.TextAlignment
26+
27+
import scala.collection.mutable.ListBuffer
28+
import scala.collection.JavaConverters._
29+
30+
/**
31+
* Export search and retrieve results to .csv file.
32+
*
33+
* @author Lisa Nguyen Quang Do
34+
* @author Ben Hermann
35+
*
36+
*/
37+
38+
class CsvOutput(config: Config) {
39+
40+
def exportResult(value: Any): Unit = {
41+
var table = value match {
42+
case results : Seq[Result] if results.head.isInstanceOf[Result] => resultsToCsv(results)
43+
case _ => {
44+
println("Error: results are in unknown format.")
45+
return
46+
}
47+
}
48+
49+
val outputFile = new BufferedWriter(new FileWriter(config.csv, /* append = */false))
50+
val csvWriter = new CSVWriter(outputFile)
51+
csvWriter.writeAll(seqAsJavaList(table))
52+
outputFile.close()
53+
println("Results written to file '" + config.csv + "'")
54+
}
55+
56+
def resultsToCsv(results : Seq[Result]) : Seq[Array[String]] = {
57+
if (results.size != 0) {
58+
val fieldNames = results.head.fieldNames()
59+
val tableHeader : Array[String] = (fieldNames.+:("discovered at").+:("version").+:("groupId").+:("artifactId").+:("source").+:("Id")).toArray
60+
val tableBody: Seq[Array[String]] = results.map {
61+
e => {
62+
Array(e.id, e.metadata.source, e.metadata.artifactId, e.metadata.groupId, e.metadata.version, e.metadata.discovered).++(fieldNames.map(f => e.metricResults(f).toString))
63+
}
64+
}
65+
return tableBody.+:(tableHeader)
66+
}
67+
return Seq.empty[Array[String]]
68+
}
69+
}

src/main/scala/de/upb/cs/swt/delphi/cli/DelphiCLI.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ object DelphiCLI extends App {
3535

3636
val cliParser = {
3737
new scopt.OptionParser[Config]("delphi-cli") {
38-
head("Delphi Command Line Tool", s"(${BuildInfo.version})")
38+
head("Delphi Command Line Tool", s"(Lala)") // ${BuildInfo.version}
3939

4040
version("version").text("Prints the version of the command line tool.")
4141

@@ -55,15 +55,16 @@ object DelphiCLI extends App {
5555
.children(
5656
arg[String]("id").action((x, c) => c.copy(id = x)).text("The ID of the project to retrieve"),
5757
opt[Unit]('f', "file").action((_, c) => c.copy(opts = List("file"))).text("Use to load the ID from file, " +
58-
"with the filepath given in place of the ID")
58+
"with the filepath given in place of the ID"), opt[String]("csv").action((x, c) => c.copy(csv = x)).text("Path to the output .csv file (overwrites existing file)")
5959
)
6060

6161
cmd("search").action((s, c) => c.copy(mode = "search"))
6262
.text("Search artifact using a query.")
6363
.children(
6464
arg[String]("query").action((x,c) => c.copy(query = x)).text("The query to be used."),
6565
opt[Int]("limit").action((x, c) => c.copy(limit = Some(x))).text("The maximal number of results returned."),
66-
opt[Unit](name="list").action((_, c) => c.copy(list = true)).text("Output results as list (raw option overrides this)")
66+
opt[Unit](name="list").action((_, c) => c.copy(list = true)).text("Output results as list (raw option overrides this)"),
67+
opt[String]("csv").action((x, c) => c.copy(csv = x)).text("Path to the output .csv file (overwrites existing file)")
6768
)
6869
}
6970
}

src/main/scala/de/upb/cs/swt/delphi/cli/artifacts/SearchResult.scala

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,23 @@ package de.upb.cs.swt.delphi.cli.artifacts
1818

1919
import spray.json.DefaultJsonProtocol
2020

21-
case class RetrieveResult(val id: String,
22-
val metadata: ArtifactMetadata,
23-
val metricResults: Map[String, Int]) {
21+
trait Result{
22+
val id: String
23+
val metadata: ArtifactMetadata
24+
val metricResults: Map[String, Int]
25+
2426
def toMavenIdentifier() : String = s"${metadata.groupId}:${metadata.artifactId}:${metadata.version}"
2527

2628
def fieldNames() : List[String] = metricResults.keys.toList.sorted
2729
}
2830

29-
case class SearchResult(val id: String,
30-
val metadata: ArtifactMetadata,
31-
val metricResults: Map[String, Int]) {
32-
def toMavenIdentifier() : String = s"${metadata.groupId}:${metadata.artifactId}:${metadata.version}"
31+
case class SearchResult(id: String,
32+
metadata: ArtifactMetadata,
33+
metricResults: Map[String, Int]) extends Result
3334

34-
def fieldNames() : List[String] = metricResults.keys.toList.sorted
35-
}
35+
case class RetrieveResult(id: String,
36+
metadata: ArtifactMetadata,
37+
metricResults: Map[String, Int]) extends Result
3638

3739
case class ArtifactMetadata(val artifactId: String,
3840
val source: String,

src/main/scala/de/upb/cs/swt/delphi/cli/commands/Command.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,6 @@ trait Command {
8080
protected def error(implicit config: Config): String => Unit = config.consoleOutput.outputError _
8181
protected def success(implicit config: Config): String => Unit = config.consoleOutput.outputSuccess _
8282

83+
protected def exportResult(implicit config: Config): Any => Unit = config.csvOutput.exportResult _
84+
8385
}

src/main/scala/de/upb/cs/swt/delphi/cli/commands/RetrieveCommand.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import akka.stream.ActorMaterializer
2323
import de.upb.cs.swt.delphi.cli.Config
2424
import de.upb.cs.swt.delphi.cli.artifacts.RetrieveResult
2525
import de.upb.cs.swt.delphi.cli.artifacts.SearchResultJson._
26+
import de.upb.cs.swt.delphi.cli.commands.SearchCommand.information
2627
import spray.json.DefaultJsonProtocol
2728

2829
import scala.concurrent.Await
@@ -62,7 +63,9 @@ object RetrieveCommand extends Command with SprayJsonSupport with DefaultJsonPro
6263
result.map(s => {
6364
if (config.raw) {
6465
reportResult(config)(s)
65-
} else {
66+
}
67+
68+
if (!config.raw || !config.csv.equals("")) {
6669
val unmarshalledFuture = Unmarshal(s).to[List[RetrieveResult]]
6770

6871
unmarshalledFuture.transform {
@@ -71,6 +74,9 @@ object RetrieveCommand extends Command with SprayJsonSupport with DefaultJsonPro
7174
success(config)(s"Found ${unmarshalled.size} item(s).")
7275
reportResult(config)(unmarshalled)
7376

77+
if(!config.csv.equals(""))
78+
exportResult(config)(unmarshalled)
79+
7480
Success(unmarshalled)
7581
}
7682
case Failure(e) => {

src/main/scala/de/upb/cs/swt/delphi/cli/commands/SearchCommand.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ object SearchCommand extends Command with SprayJsonSupport with DefaultJsonProto
7777

7878
if (config.raw || result.equals("")) {
7979
reportResult(config)(result)
80-
} else {
80+
}
81+
82+
if(!(config.raw || result.equals("")) || !config.csv.equals("")) {
8183
val unmarshalledFuture = Unmarshal(result).to[List[SearchResult]]
8284

8385
val processFuture = unmarshalledFuture.transform {
@@ -108,6 +110,9 @@ object SearchCommand extends Command with SprayJsonSupport with DefaultJsonProto
108110
reportResult(config)(results)
109111

110112
information(config)(f"Query took $queryRuntime%.2fs.")
113+
114+
if(!config.csv.equals(""))
115+
exportResult(config)(results)
111116
}
112117

113118
case class Query(query: String,

0 commit comments

Comments
 (0)