Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

[#222] No info to user about invalid regex #272

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion core/src/main/scala/codesearch/core/db/DefaultDB.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ trait DefaultDB[T <: DefaultTable] {
pack.name,
pack.version,
new Timestamp(System.currentTimeMillis())
))
)
)
IO.fromFuture(IO(db.run(insOrUpdate)))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package codesearch.core.index.directory

import java.io.File
import java.nio.file.Path

import cats.effect.Sync
Expand Down Expand Up @@ -45,9 +44,13 @@ private[index] trait Extractor {
val dir = unarchived.toFile
dir.listFiles
.filter(_.isDirectory)
.foreach(_.listFiles.foreach(file =>
if (file.isDirectory) moveDirectoryToDirectory(file, dir, false)
else moveFileToDirectory(file, dir, false)))
.foreach(
_.listFiles.foreach(
file =>
if (file.isDirectory) moveDirectoryToDirectory(file, dir, false)
else moveFileToDirectory(file, dir, false)
)
)
unarchived
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package codesearch.core.index.repository

import java.io.File
import java.nio.ByteBuffer
import java.nio.file.Path
import java.nio.file.StandardOpenOption.{CREATE, TRUNCATE_EXISTING}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package codesearch.core.regex.lexer

import fastparse._
import NoWhitespace._
import codesearch.core.regex.lexer.tokens._
import fastparse.NoWhitespace._
import fastparse._

object Tokenizer {

Expand Down Expand Up @@ -46,5 +46,7 @@ object Tokenizer {
private def parserAnyStringBeforeSpecialSymbol[_: P] = P((!" " ~ !specialSymbols ~ AnyChar).rep(1).!.map(Literal))

private def parseStringWithSpecialSymbols[_: P] =
P(parserEscaped | parserCharSet | parserAnyStringBeforeSpecialSymbol | parseSpaces | parseRepetitionSeq | parserSpecialSymbol).rep
P(
parserEscaped | parserCharSet | parserAnyStringBeforeSpecialSymbol | parseSpaces | parseRepetitionSeq | parserSpecialSymbol
).rep
}
100 changes: 67 additions & 33 deletions core/src/main/scala/codesearch/core/search/Search.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package codesearch.core.search

import java.net.URLDecoder
import java.nio.file.{Path => NioPath}
import java.util.regex.Pattern

import ammonite.ops.{Path, pwd}
import cats.data.NonEmptyVector
Expand All @@ -10,15 +11,15 @@ import cats.syntax.option._
import codesearch.core.config.{Config, SnippetConfig}
import codesearch.core.index.directory.СindexDirectory
import codesearch.core.index.repository.Extensions
import codesearch.core.search.Search.{CSearchPage, CSearchResult, CodeSnippet, Package, PackageResult, snippetConfig}
import codesearch.core.regex.RegexConstructor
import codesearch.core.search.Search.{CSearchPage, CSearchResult, CodeSnippet, ErrorResponse, Package, PackageResult, Response, SearchByIndexResult, snippetConfig}
import codesearch.core.search.SnippetsGrouper.SnippetInfo
import codesearch.core.util.Helper.readFileAsync
import fs2.{Pipe, Stream}
import io.chrisdavenport.log4cats.SelfAwareStructuredLogger
import io.chrisdavenport.log4cats.slf4j.Slf4jLogger
import codesearch.core.regex.RegexConstructor

import scala.sys.process.Process
import scala.sys.process.{Process, ProcessLogger}

trait Search {

Expand All @@ -29,21 +30,33 @@ trait Search {

implicit val root: NioPath = cindexDir.root

def search(request: SearchRequest): IO[CSearchPage] = {
for {
lines <- csearch(request)
results <- Stream
.emits(lines)
.through(SnippetsGrouper.groupLines(snippetConfig))
.drop(snippetConfig.pageSize * (request.page - 1))
.take(snippetConfig.pageSize)
.evalMap(createSnippet)
.through(groupByPackage)
.compile
.toList
} yield CSearchPage(results.sortBy(_.pack.name), lines.size)
def search(request: SearchRequest): IO[Response] = {
checkRegexpForValid(request.query).attempt.flatMap {
case Left(error) =>
IO(createErrorResponse(error))
case Right(_) =>
val entity = csearch(request)
for {
results <- Stream
.emits(entity.lists)
.through(SnippetsGrouper.groupLines(snippetConfig))
.drop(snippetConfig.pageSize * (request.page - 1))
.take(snippetConfig.pageSize)
.evalMap(createSnippet)
.through(groupByPackage)
.compile
.toList
} yield CSearchPage(results.sortBy(_.pack.name), entity.lists.length)
}
}

def checkRegexpForValid(regexp: String): IO[Pattern] = {
IO { Pattern.compile(regexp) }
}

private def createErrorResponse(error: Throwable): ErrorResponse =
ErrorResponse(error.getMessage.substring(0, 1).toUpperCase + error.getMessage.substring(1, error.getMessage.length))

/**
* Build package name and path to remote repository
*
Expand All @@ -69,14 +82,15 @@ trait Search {
*/
protected def buildRepUrl(packageName: String, version: String): String

private def csearch(request: SearchRequest): IO[List[String]] = {
private def csearch(request: SearchRequest): SearchByIndexResult = {
val indexDir = cindexDir.indexDirAs[String]
val env = ("CSEARCHINDEX", indexDir)

for {
_ <- logger.debug(s"running CSEARCHINDEX=$indexDir ${arguments(request).mkString(" ")}")
results <- IO((Process(arguments(request), None, env) #| Seq("head", "-1001")).lineStream.toList)
} yield results
var stderr = new String
val log = ProcessLogger((o: String) => o, (e: String) => stderr = e)
Kabowyad marked this conversation as resolved.
Show resolved Hide resolved
val test = for {
results <- IO((Process(arguments(request), None, env) #| Seq("head", "-1001")).lineStream_!(log).toList)
} yield SearchByIndexResult(results, ErrorResponse(stderr))
test.unsafeRunSync()
}

private def arguments(request: SearchRequest): List[String] = {
Expand Down Expand Up @@ -148,17 +162,6 @@ object Search {
.map(_.snippetConfig)
.unsafeRunSync()

/**
* result of searching
*
* @param data code snippets grouped by package
* @param total number of total matches
*/
final case class CSearchPage(
data: Seq[PackageResult],
total: Int
)

/**
*
* @param relativePath path into package sources
Expand Down Expand Up @@ -203,4 +206,35 @@ object Search {
pack: Package,
result: CodeSnippet
)

sealed trait Response

/**
* result of searching
*
* @param data code snippets grouped by package
* @param total number of total matches
*/
final case class CSearchPage(
data: Seq[PackageResult],
Kabowyad marked this conversation as resolved.
Show resolved Hide resolved
total: Int
) extends Response

final case class SearchByIndexResult(lists: List[String], error: ErrorResponse)
final case class ErrorResponse(message: String) extends Response
final case class SuccessResponse(
updated: String,
packages: Seq[PackageResult],
query: String,
filter: Option[String],
filePath: Option[String],
insensitive: Boolean,
space: Boolean,
precise: Boolean,
sources: Boolean,
page: Int,
totalMatches: Int,
callURI: String,
lang: String
) extends Response
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ case class SearchRequest(
def stringify(x: Boolean): String = if (x) "on" else "off"

uri"$host/$lang/search?query=$query&filter=$filter&filePath=$filePath&insensitive=${stringify(insensitive)}&space=${stringify(
spaceInsensitive)}&precise=${stringify(preciseMatch)}&sources=${stringify(sourcesOnly)}"
spaceInsensitive
)
}&precise=${stringify(preciseMatch)}&sources=${stringify(sourcesOnly)}"
}
}

Expand All @@ -57,7 +59,7 @@ object SearchRequest {
isEnabled(spaceInsensitive),
isEnabled(preciseMatch),
isEnabled(sourcesOnly),
page.toInt,
page.toInt
)
}

Expand Down
42 changes: 26 additions & 16 deletions core/src/test/scala/codesearch/core/regex/lexer/TokenizerSpec.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package codesearch.core.regex.lexer

import scala.io.Source
import org.scalatest.{FreeSpec, Matchers}
import codesearch.core.regex.lexer.tokens._
import org.scalatest.{FreeSpec, Matchers}

import scala.io.Source

class TokenizerSpec extends FreeSpec with Matchers {

Expand All @@ -25,17 +26,21 @@ class TokenizerSpec extends FreeSpec with Matchers {

testParseAndRender(
"Hello World + ?",
Seq(Literal("Hello"),
Space(" "),
Literal("World"),
Space(" "),
SpecialSymbol("+"),
Space(" "),
SpecialSymbol("?"))
Seq(
Literal("Hello"),
Space(" "),
Literal("World"),
Space(" "),
SpecialSymbol("+"),
Space(" "),
SpecialSymbol("?")
)
)

testParseAndRender("Hello World [^Gared]",
Seq(Literal("Hello"), Space(" "), Literal("World"), Space(" "), CharSet("[^Gared]")))
testParseAndRender(
"Hello World [^Gared]",
Seq(Literal("Hello"), Space(" "), Literal("World"), Space(" "), CharSet("[^Gared]"))
)

testParseAndRender(
"Hello World [^Gared] (Bale) \\Symbol",
Expand Down Expand Up @@ -101,12 +106,16 @@ class TokenizerSpec extends FreeSpec with Matchers {
testParseAndRender("|", Seq(SpecialSymbol("|")))
testParseAndRender("^", Seq(SpecialSymbol("^")))
testParseAndRender("$", Seq(SpecialSymbol("$")))
testParseAndRender("ax.,.c",
Seq(Literal("ax"), SpecialSymbol("."), Literal(","), SpecialSymbol("."), Literal("c")))
testParseAndRender(
"ax.,.c",
Seq(Literal("ax"), SpecialSymbol("."), Literal(","), SpecialSymbol("."), Literal("c"))
)
testParseAndRender("a|^", Seq(Literal("a"), SpecialSymbol("|"), SpecialSymbol("^")))
testParseAndRender("a|b", Seq(Literal("a"), SpecialSymbol("|"), Literal("b")))
testParseAndRender("(a)|b",
Seq(SpecialSymbol("("), Literal("a"), SpecialSymbol(")"), SpecialSymbol("|"), Literal("b")))
testParseAndRender(
"(a)|b",
Seq(SpecialSymbol("("), Literal("a"), SpecialSymbol(")"), SpecialSymbol("|"), Literal("b"))
)
testParseAndRender("a*", Seq(Literal("a"), SpecialSymbol("*")))
testParseAndRender("a??", Seq(Literal("a"), SpecialSymbol("?"), SpecialSymbol("?")))
}
Expand All @@ -121,7 +130,8 @@ class TokenizerSpec extends FreeSpec with Matchers {
testParseAndRender("a{2,3}", Seq(Literal("a"), RepetitionSeq("{2,3}")))
testParseAndRender(
"a{2, 3}",
Seq(Literal("a"), SpecialSymbol("{"), Literal("2,"), Space(" "), Literal("3"), SpecialSymbol("}")))
Seq(Literal("a"), SpecialSymbol("{"), Literal("2,"), Space(" "), Literal("3"), SpecialSymbol("}"))
)
testParseAndRender("a{,3}", Seq(Literal("a"), SpecialSymbol("{"), Literal(",3"), SpecialSymbol("}")))
testParseAndRender("a{2,}", Seq(Literal("a"), RepetitionSeq("{2,}")))
testParseAndRender("a{,}", Seq(Literal("a"), SpecialSymbol("{"), Literal(","), SpecialSymbol("}")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class SnippetsGrouperSpec extends WordSpec with Matchers {
"3models/0.3.0/Graphics/Model/DirectX.hs:14:import Data.Attoparsec.ByteString.Char8 as A",
"3models/0.3.0/Graphics/Model/DirectX.hs:15:import qualified Data.ByteString as B",
"3models/0.3.0/Graphics/Model/DirectX.hs:16:import Data.Traversable",
"3models/0.3.0/Graphics/Model/DirectX.hs:17:import Data.Word",
"3models/0.3.0/Graphics/Model/DirectX.hs:17:import Data.Word"
)

val snippets: List[SnippetInfo] = fs2.Stream
Expand All @@ -37,7 +37,7 @@ class SnippetsGrouperSpec extends WordSpec with Matchers {

val matchedLines = Seq(
"3models/0.3.0/Graphics/Model/DirectX.hs:28:} deriving Show",
"3models/0.3.0/Graphics/Model/DirectX.hs:39:} deriving Show",
"3models/0.3.0/Graphics/Model/DirectX.hs:39:} deriving Show"
)

val snippets: List[SnippetInfo] = fs2.Stream
Expand All @@ -64,7 +64,7 @@ class SnippetsGrouperSpec extends WordSpec with Matchers {

val matchedLines = Seq(
"3models/0.3.0/Graphics/Model/DirectX.hs:14:import Data.Attoparsec.ByteString.Char8 as A",
"3models/0.3.0/Graphics/Model/Obj.hs:16:import Data.Attoparsec.ByteString.Char8 as A",
"3models/0.3.0/Graphics/Model/Obj.hs:16:import Data.Attoparsec.ByteString.Char8 as A"
)

val snippets: List[SnippetInfo] = fs2.Stream
Expand Down
4 changes: 2 additions & 2 deletions core/src/test/scala/integration/TestFixture.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.nio.ByteBuffer
import java.nio.file.Paths

import cats.effect.{IO, Resource}
import codesearch.core.{BlockingEC, config}
import codesearch.core.BlockingEC
import codesearch.core.config._
import com.softwaremill.sttp.SttpBackend
import com.softwaremill.sttp.asynchttpclient.fs2.AsyncHttpClientFs2Backend
Expand Down Expand Up @@ -33,7 +33,7 @@ trait TestFixture {
port = 5432,
name = "sourcesdb",
user = "postgres",
password = "postgres",
password = "postgres"
),
SnippetConfig(
pageSize = 30,
Expand Down
3 changes: 2 additions & 1 deletion project/Builder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ object Builder {
"org.codehaus.janino" % "janino" % "3.0.11",
"com.typesafe.play" %% "play-json" % "2.6.9",
"com.github.mpilquist" %% "simulacrum" % "0.13.0",
"org.typelevel" %% "cats-core" % "1.2.0"
"org.typelevel" %% "cats-core" % "1.2.0",
"com.google.re2j" % "re2j" % "1.2"
Kabowyad marked this conversation as resolved.
Show resolved Hide resolved
)
)

Expand Down
9 changes: 6 additions & 3 deletions web-server/app/codesearch/web/controllers/Application.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,18 @@ class Application @Inject()(
.zip(NpmDB.updated.zip(NpmDB.getSize))
.zip(GemDB.updated.zip(GemDB.getSize))
.map {
case ((((updatedHackage, sizeHackage), (updatedCrates, sizeCrates)), (updatedNpm, sizeNpm)),
(updatedGem, sizeGem)) =>
case (
(((updatedHackage, sizeHackage), (updatedCrates, sizeCrates)), (updatedNpm, sizeNpm)),
(updatedGem, sizeGem)
) =>
Ok(
views.html.index(
LangInfo(updatedHackage.getTime, sizeHackage),
LangInfo(updatedCrates.getTime, sizeCrates),
LangInfo(updatedGem.getTime, sizeGem),
LangInfo(updatedNpm.getTime, sizeNpm)
))
)
)
}
}

Expand Down
3 changes: 2 additions & 1 deletion web-server/app/codesearch/web/controllers/NpmSearcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class NpmSearcher @Inject()(
) extends InjectedController with SearchController[NpmTable] {
override def db: DefaultDB[NpmTable] = new NpmDB { val db = database }
override lazy val searchEngine: JavaScriptSearch = new JavaScriptSearch(
JavaScriptCindex(Paths.get("./index/cindex/")))
JavaScriptCindex(Paths.get("./index/cindex/"))
)
override def lang: String = "js"
}
Loading