diff --git a/src/main/scala/app/IndexController.scala b/src/main/scala/app/IndexController.scala index c855255..664a55a 100644 --- a/src/main/scala/app/IndexController.scala +++ b/src/main/scala/app/IndexController.scala @@ -1,21 +1,16 @@ package app import util._ -import util.Directory._ import service._ import jp.sf.amateras.scalatra.forms._ -import org.eclipse.jgit.treewalk.TreeWalk -import org.eclipse.jgit.revwalk.RevWalk -import scala.collection.mutable.ListBuffer -import org.eclipse.jgit.lib.FileMode -import model.Issue class IndexController extends IndexControllerBase - with RepositoryService with AccountService with SystemSettingsService with ActivityService with IssuesService + with RepositoryService with AccountService with SystemSettingsService with ActivityService + with RepositorySearchService with IssuesService with ReferrerAuthenticator trait IndexControllerBase extends ControllerBase { self: RepositoryService - with SystemSettingsService with ActivityService with IssuesService + with SystemSettingsService with ActivityService with RepositorySearchService with ReferrerAuthenticator => val searchForm = mapping( @@ -41,7 +36,6 @@ } get("/:owner/:repository/search")(referrersOnly { repository => - import RepositorySearch._ val query = params("q").trim val target = params.getOrElse("type", "code") val page = try { @@ -51,114 +45,17 @@ case e: NumberFormatException => 1 } - - val SearchResult(files, issues) = searchRepository(repository.owner, repository.name, query) - target.toLowerCase match { - case "issue" => - search.html.issues(issues.map { case (issue, commentCount, content) => - IssueSearchResult( - issue.issueId, - issue.title, - issue.openedUserName, - issue.registeredDate, - commentCount, - getHighlightText(content, query)._1) - }, files.size, query, page, repository) - case _ => - JGitUtil.withGit(getRepositoryDir(repository.owner, repository.name)){ git => - val commits = JGitUtil.getLatestCommitFromPaths(git, files.toList.map(_._1), "HEAD") + case "issue" => search.html.issues( + searchIssues(repository.owner, repository.name, query), + countFiles(repository.owner, repository.name, query), + query, page, repository) - search.html.code(files.toList.map { case (path, text) => - val (highlightText, lineNumber) = getHighlightText(text, query) - FileSearchResult( - path, - commits(path).getCommitterIdent.getWhen, - highlightText, - lineNumber) - }, issues.size, query, page, repository) - } + case _ => search.html.code( + searchFiles(repository.owner, repository.name, query), + countIssues(repository.owner, repository.name, query), + query, page, repository) } }) - case class SearchResult( - files: List[(String, String)], - issues: List[(Issue, Int, String)] - ) - - def searchRepository(owner: String, repository: String, query: String): SearchResult = { - val issues = if(query.isEmpty) Nil else searchIssuesByKeyword(owner, repository, query) - val files = if(query.isEmpty) Nil else searchRepositoryFiles(owner, repository, query) - SearchResult(files, issues) - } - - private def searchRepositoryFiles(owner: String, repository: String, query: String): List[(String, String)] = { - JGitUtil.withGit(getRepositoryDir(owner, repository)){ git => - val revWalk = new RevWalk(git.getRepository) - val objectId = git.getRepository.resolve("HEAD") - val revCommit = revWalk.parseCommit(objectId) - val treeWalk = new TreeWalk(git.getRepository) - treeWalk.setRecursive(true) - treeWalk.addTree(revCommit.getTree) - - val keywords = StringUtil.splitWords(query.toLowerCase) - val list = new ListBuffer[(String, String)] - - while (treeWalk.next()) { - if(treeWalk.getFileMode(0) != FileMode.TREE){ - JGitUtil.getContent(git, treeWalk.getObjectId(0), false).foreach { bytes => - if(FileUtil.isText(bytes)){ - val text = new String(bytes, "UTF-8") - val lowerText = text.toLowerCase - val indices = keywords.map(lowerText.indexOf _) - if(!indices.exists(_ < 0)){ - list.append((treeWalk.getPathString, text)) - } - } - } - } - } - treeWalk.release - revWalk.release - - list.toList - } - } - - - private def getHighlightText(content: String, query: String): (String, Int) = { - val keywords = StringUtil.splitWords(query.toLowerCase) - val lowerText = content.toLowerCase - val indices = keywords.map(lowerText.indexOf _) - - if(!indices.exists(_ < 0)){ - val lineNumber = content.substring(0, indices.min).split("\n").size - 1 - val highlightText = StringUtil.escapeHtml(content.split("\n").drop(lineNumber).take(5).mkString("\n")) - .replaceAll("(?i)(" + keywords.map("\\Q" + _ + "\\E").mkString("|") + ")", - "$1") - (highlightText, lineNumber + 1) - } else { - (content.split("\n").take(5).mkString("\n"), 1) - } - } - } - -case class IssueSearchResult( - issueId: Int, - title: String, - openedUserName: String, - registeredDate: java.util.Date, - commentCount: Int, - highlightText: String) - -case class FileSearchResult( - path: String, - lastModified: java.util.Date, - highlightText: String, - highlightLineNumber: Int) - -object RepositorySearch extends IssuesService { - val CodeLimit = 10 - val IssueLimit = 10 -} diff --git a/src/main/scala/service/RepositorySearchService.scala b/src/main/scala/service/RepositorySearchService.scala new file mode 100644 index 0000000..669a36b --- /dev/null +++ b/src/main/scala/service/RepositorySearchService.scala @@ -0,0 +1,121 @@ +package service + +import model.Issue +import util.{FileUtil, StringUtil, JGitUtil} +import util.Directory._ +import model.Issue +import org.eclipse.jgit.revwalk.RevWalk +import org.eclipse.jgit.treewalk.TreeWalk +import scala.collection.mutable.ListBuffer +import org.eclipse.jgit.lib.FileMode +import org.eclipse.jgit.api.Git + +trait RepositorySearchService { self: IssuesService => + import RepositorySearchService._ + + def countIssues(owner: String, repository: String, query: String): Int = + searchIssuesByKeyword(owner, repository, query).length + + def searchIssues(owner: String, repository: String, query: String): List[IssueSearchResult] = + searchIssuesByKeyword(owner, repository, query).map { case (issue, commentCount, content) => + IssueSearchResult( + issue.issueId, + issue.title, + issue.openedUserName, + issue.registeredDate, + commentCount, + getHighlightText(content, query)._1) + } + + def countFiles(owner: String, repository: String, query: String): Int = + JGitUtil.withGit(getRepositoryDir(owner, repository)){ git => + searchRepositoryFiles(git, query).length + } + + def searchFiles(owner: String, repository: String, query: String): List[FileSearchResult] = + JGitUtil.withGit(getRepositoryDir(owner, repository)){ git => + val files = searchRepositoryFiles(git, query) + val commits = JGitUtil.getLatestCommitFromPaths(git, files.toList.map(_._1), "HEAD") + files.map { case (path, text) => + val (highlightText, lineNumber) = getHighlightText(text, query) + FileSearchResult( + path, + commits(path).getCommitterIdent.getWhen, + highlightText, + lineNumber) + } + } + + private def searchRepositoryFiles(git: Git, query: String): List[(String, String)] = { + val revWalk = new RevWalk(git.getRepository) + val objectId = git.getRepository.resolve("HEAD") + val revCommit = revWalk.parseCommit(objectId) + val treeWalk = new TreeWalk(git.getRepository) + treeWalk.setRecursive(true) + treeWalk.addTree(revCommit.getTree) + + val keywords = StringUtil.splitWords(query.toLowerCase) + val list = new ListBuffer[(String, String)] + + while (treeWalk.next()) { + if(treeWalk.getFileMode(0) != FileMode.TREE){ + JGitUtil.getContent(git, treeWalk.getObjectId(0), false).foreach { bytes => + if(FileUtil.isText(bytes)){ + val text = new String(bytes, "UTF-8") + val lowerText = text.toLowerCase + val indices = keywords.map(lowerText.indexOf _) + if(!indices.exists(_ < 0)){ + list.append((treeWalk.getPathString, text)) + } + } + } + } + } + treeWalk.release + revWalk.release + + list.toList + } + +} + +object RepositorySearchService { + + val CodeLimit = 10 + val IssueLimit = 10 + + def getHighlightText(content: String, query: String): (String, Int) = { + val keywords = StringUtil.splitWords(query.toLowerCase) + val lowerText = content.toLowerCase + val indices = keywords.map(lowerText.indexOf _) + + if(!indices.exists(_ < 0)){ + val lineNumber = content.substring(0, indices.min).split("\n").size - 1 + val highlightText = StringUtil.escapeHtml(content.split("\n").drop(lineNumber).take(5).mkString("\n")) + .replaceAll("(?i)(" + keywords.map("\\Q" + _ + "\\E").mkString("|") + ")", + "$1") + (highlightText, lineNumber + 1) + } else { + (content.split("\n").take(5).mkString("\n"), 1) + } + } + + case class SearchResult( + files : List[(String, String)], + issues: List[(Issue, Int, String)]) + + case class IssueSearchResult( + issueId: Int, + title: String, + openedUserName: String, + registeredDate: java.util.Date, + commentCount: Int, + highlightText: String) + + case class FileSearchResult( + path: String, + lastModified: java.util.Date, + highlightText: String, + highlightLineNumber: Int) + +} \ No newline at end of file diff --git a/src/main/twirl/search/code.scala.html b/src/main/twirl/search/code.scala.html index 7dca4a4..20b08a6 100644 --- a/src/main/twirl/search/code.scala.html +++ b/src/main/twirl/search/code.scala.html @@ -1,10 +1,11 @@ -@(files: List[app.FileSearchResult], +@(files: List[service.RepositorySearchService.FileSearchResult], issueCount: Int, query: String, page: Int, repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context) @import context._ @import view.helpers._ +@import service.RepositorySearchService._ @html.main("Search Results", Some(repository)){ @menu("code", files.size, issueCount, query, repository){ @if(files.isEmpty){ @@ -12,14 +13,14 @@ } else {