(refs #3)Start work for repository search.

This commit is contained in:
takezoe
2013-07-17 03:24:47 +09:00
parent cb591925ea
commit 79ec96343f
3 changed files with 105 additions and 5 deletions

View File

@@ -1,13 +1,28 @@
package app package app
import util._
import util.Directory._
import service._ import service._
import jp.sf.amateras.scalatra.forms._
import org.eclipse.jgit.api.Git
import org.apache.commons.io.FileUtils
class IndexController extends IndexControllerBase class IndexController extends IndexControllerBase
with RepositoryService with AccountService with SystemSettingsService with ActivityService with RepositoryService with AccountService with SystemSettingsService with ActivityService
with ReferrerAuthenticator
trait IndexControllerBase extends ControllerBase { self: RepositoryService trait IndexControllerBase extends ControllerBase { self: RepositoryService
with SystemSettingsService with ActivityService => with SystemSettingsService with ActivityService
with ReferrerAuthenticator =>
val searchForm = mapping(
"query" -> trim(text(required)), // TODO optional?
"owner" -> trim(text(required)),
"repository" -> trim(text(required))
)(SearchForm.apply)
case class SearchForm(query: String, owner: String, repository: String)
get("/"){ get("/"){
val loginAccount = context.loginAccount val loginAccount = context.loginAccount
@@ -18,4 +33,60 @@ trait IndexControllerBase extends ControllerBase { self: RepositoryService
) )
} }
} post("/search", searchForm){ form =>
redirect(s"${form.owner}/${form.repository}/search?q=${StringUtil.urlEncode(form.query)}")
}
// TODO readable only
get("/:owner/:repository/search")(referrersOnly { repository =>
val owner = params("owner")
val name = params("repository")
val query = params("q")
val target = params.getOrElse("type", "Code")
target.toLowerCase match {
case "issue" => {
// TODO search issue
}
case _ => {
JGitUtil.withGit(getRepositoryDir(owner, name)){ git =>
// TODO search code
val dir = new java.io.File(getTemporaryDir(owner, name), "search")
if(!dir.exists){
val git = Git
.cloneRepository.setDirectory(dir)
.setURI(getRepositoryDir(owner, name).toURI.toString)
.setBranch(repository.repository.defaultBranch)
.call
git.getRepository.close
} else {
val git = Git.open(dir)
git.pull.call
if(git.getRepository.getBranch != repository.repository.defaultBranch){
git.checkout.setName(repository.repository.defaultBranch).call
}
git.getRepository.close
}
search.html.code(searchDirectory(query, dir).map { file =>
FileSearchResult(
file.getAbsolutePath.substring(dir.getAbsolutePath.length + 1).replace('\\', '/'),
new java.util.Date(file.lastModified)
)
}, query, repository)
}
}
}
})
private def searchDirectory(query: String, dir: java.io.File, matched: List[java.io.File] = Nil): List[java.io.File] = {
dir.listFiles.toList.flatMap {
case file if(file.isDirectory && file.getName != ".git") => searchDirectory(query, file, matched)
case file if(file.isFile && FileUtils.readFileToString(file).contains(query)) => matched :+ file
case _ => matched
}
}
}
case class FileSearchResult(path: String, lastModified: java.util.Date)

View File

@@ -29,7 +29,7 @@
<script src="@assets/zclip/ZeroClipboard.min.js"></script> <script src="@assets/zclip/ZeroClipboard.min.js"></script>
</head> </head>
<body> <body>
<form action="@path/search" method="GET"> <form id="search" action="@path/search" method="POST">
<div class="navbar"> <div class="navbar">
<div class="navbar-inner"> <div class="navbar-inner">
<div class="container"> <div class="container">
@@ -41,7 +41,13 @@
<a class="brand" href="@path/">GitBucket</a> <a class="brand" href="@path/">GitBucket</a>
<div class="nav-collapse collapse pull-right"> <div class="nav-collapse collapse pull-right">
@repository.map { repository => @repository.map { repository =>
<input type="text" name="query" style="width: 300px;margin-top: 5px; margin-bottom: 0px;" placeholder="Search this repository"/> @if(loginAccount.isDefined){
<input type="text" name="query" style="width: 300px; margin-top: 0px; margin-bottom: 0px;" placeholder="Search this repository"/>
} else {
<input type="text" name="query" style="width: 300px; margin-top: 5px; margin-bottom: 0px;" placeholder="Search this repository"/>
}
<input type="hidden" name="owner" value="@repository.owner"/>
<input type="hidden" name="repository" value="@repository.name"/>
} }
@if(loginAccount.isDefined){ @if(loginAccount.isDefined){
<a href="@url(loginAccount.get.userName)" class="username menu">@avatar(loginAccount.get.userName, 20) @loginAccount.get.userName</a> <a href="@url(loginAccount.get.userName)" class="username menu">@avatar(loginAccount.get.userName, 20) @loginAccount.get.userName</a>
@@ -65,5 +71,12 @@
<div class="container body"> <div class="container body">
@body @body
</div> </div>
<script>
$(function(){
$('#search').submit(function(){
return $.trim($(this).find('input[name=query]').val()) != '';
});
});
</script>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,16 @@
@(files: List[app.FileSearchResult], query: String, repository: service.RepositoryService.RepositoryInfo)(implicit context: app.Context)
@import context._
@import view.helpers._
@html.main("Search Results", Some(repository)){
@if(files.isEmpty){
<h4>We couldn't find any code matching '@query'</h4>
} else {
<h4>We've found @files.size code @plural(files.size, "result")</h4>
}
@files.map { file =>
<div>
<div><a href="@url(repository)/blob/@repository.repository.defaultBranch/@file.path">@file.path</a></div>
<div class="muted">@datetime(file.lastModified)</div>
</div>
}
}