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 all 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
}
95 changes: 64 additions & 31 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,13 +11,13 @@ 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

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,14 @@ 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(" ")}")
val test = for {
_ <- logger.debug(s"running CSEARCHINDEX=$indexDir ${arguments(request).mkString(" ")}")
results <- IO((Process(arguments(request), None, env) #| Seq("head", "-1001")).lineStream.toList)
} yield results
} yield SearchByIndexResult(results, ErrorResponse("Regular expression is wrong. Check it"))
test.unsafeRunSync()
}

private def arguments(request: SearchRequest): List[String] = {
Expand Down Expand Up @@ -148,17 +161,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 +205,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
12 changes: 8 additions & 4 deletions core/src/test/scala/integration/IntegrationSpecBase.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package integration

import codesearch.core.search.Search.PackageResult
import codesearch.core.search.Search.{PackageResult, SuccessResponse}
import codesearch.core.search.{Search, SearchRequest}
import slick.jdbc.PostgresProfile.api._
import com.dimafeng.testcontainers.PostgreSQLContainer
import org.scalatest.Matchers
import slick.jdbc.PostgresProfile.api._

trait IntegrationSpecBase extends Matchers {

Expand All @@ -21,7 +21,11 @@ trait IntegrationSpecBase extends Matchers {
.search(lookFor)
.unsafeRunSync()

searchResult.total shouldBe totalResults
searchResult.data shouldBe result
searchResult match {
case x: SuccessResponse => {
x.totalMatches shouldBe totalResults
x.packages shouldBe result
}
}
}
}
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
Loading