Bump to Lucene 5.5.2 The new code will create Lucene indices in a new directory named after codec and index version. This provides for easy and safe up- and downgrades. But it also means that the old indices will stick around on disk. What this version is missing is a kind of "garbage collection" deleting old, unused indices when they are no longer needed. That task needs to be done manually currently. We should at leas at some point provide a script for it.tags/r1.9.0
@@ -21,13 +21,13 @@ | |||
<classpathentry kind="lib" path="ext/wicket-1.4.22.jar" sourcepath="ext/src/wicket-1.4.22.jar" /> | |||
<classpathentry kind="lib" path="ext/wicket-auth-roles-1.4.22.jar" sourcepath="ext/src/wicket-auth-roles-1.4.22.jar" /> | |||
<classpathentry kind="lib" path="ext/wicket-extensions-1.4.22.jar" sourcepath="ext/src/wicket-extensions-1.4.22.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-core-4.10.4.jar" sourcepath="ext/src/lucene-core-4.10.4.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-analyzers-common-4.10.4.jar" sourcepath="ext/src/lucene-analyzers-common-4.10.4.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-highlighter-4.10.4.jar" sourcepath="ext/src/lucene-highlighter-4.10.4.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-memory-4.10.4.jar" sourcepath="ext/src/lucene-memory-4.10.4.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-queries-4.10.4.jar" sourcepath="ext/src/lucene-queries-4.10.4.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-queryparser-4.10.4.jar" sourcepath="ext/src/lucene-queryparser-4.10.4.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-sandbox-4.10.4.jar" sourcepath="ext/src/lucene-sandbox-4.10.4.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-core-5.5.2.jar" sourcepath="ext/src/lucene-core-5.5.2.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-analyzers-common-5.5.2.jar" sourcepath="ext/src/lucene-analyzers-common-5.5.2.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-highlighter-5.5.2.jar" sourcepath="ext/src/lucene-highlighter-5.5.2.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-memory-5.5.2.jar" sourcepath="ext/src/lucene-memory-5.5.2.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-queries-5.5.2.jar" sourcepath="ext/src/lucene-queries-5.5.2.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-queryparser-5.5.2.jar" sourcepath="ext/src/lucene-queryparser-5.5.2.jar" /> | |||
<classpathentry kind="lib" path="ext/lucene-sandbox-5.5.2.jar" sourcepath="ext/src/lucene-sandbox-5.5.2.jar" /> | |||
<classpathentry kind="lib" path="ext/jakarta-regexp-1.4.jar" /> | |||
<classpathentry kind="lib" path="ext/pegdown-1.5.0.jar" sourcepath="ext/src/pegdown-1.5.0.jar" /> | |||
<classpathentry kind="lib" path="ext/parboiled-java-1.1.7.jar" sourcepath="ext/src/parboiled-java-1.1.7.jar" /> |
@@ -106,7 +106,7 @@ properties: { | |||
jetty.version : 9.2.13.v20150730 | |||
slf4j.version : 1.7.12 | |||
wicket.version : 1.4.22 | |||
lucene.version : 4.10.4 | |||
lucene.version : 5.5.2 | |||
jgit.version : 4.1.1.201511131810-r | |||
groovy.version : 2.4.4 | |||
bouncycastle.version : 1.52 | |||
@@ -146,9 +146,9 @@ dependencies: | |||
- compile 'org.apache.wicket:wicket-extensions:${wicket.version}' :war !org.mockito | |||
- compile 'org.apache.lucene:lucene-core:${lucene.version}' :war :fedclient | |||
- compile 'org.apache.lucene:lucene-analyzers-common:${lucene.version}' :war :fedclient | |||
- compile 'org.apache.lucene:lucene-highlighter:${lucene.version}' :war :fedclient | |||
- compile 'org.apache.lucene:lucene-highlighter:${lucene.version}' :war :fedclient !org.apache.lucene:lucene-join | |||
- compile 'org.apache.lucene:lucene-memory:${lucene.version}' :war :fedclient | |||
- compile 'org.apache.lucene:lucene-queryparser:${lucene.version}' :war :fedclient | |||
- compile 'org.apache.lucene:lucene-queryparser:${lucene.version}' :war :fedclient !org.apache.lucene:lucene-spatial | |||
- compile 'org.pegdown:pegdown:1.5.0' :war | |||
- compile 'org.fusesource.wikitext:wikitext-core:${wikitext.version}' :war | |||
- compile 'org.fusesource.wikitext:twiki-core:${wikitext.version}' :war |
@@ -180,79 +180,79 @@ | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module-library"> | |||
<library name="lucene-core-4.10.4.jar"> | |||
<library name="lucene-core-5.5.2.jar"> | |||
<CLASSES> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-core-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-core-5.5.2.jar!/" /> | |||
</CLASSES> | |||
<JAVADOC /> | |||
<SOURCES> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-core-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-core-5.5.2.jar!/" /> | |||
</SOURCES> | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module-library"> | |||
<library name="lucene-analyzers-common-4.10.4.jar"> | |||
<library name="lucene-analyzers-common-5.5.2.jar"> | |||
<CLASSES> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-analyzers-common-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-analyzers-common-5.5.2.jar!/" /> | |||
</CLASSES> | |||
<JAVADOC /> | |||
<SOURCES> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-analyzers-common-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-analyzers-common-5.5.2.jar!/" /> | |||
</SOURCES> | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module-library"> | |||
<library name="lucene-highlighter-4.10.4.jar"> | |||
<library name="lucene-highlighter-5.5.2.jar"> | |||
<CLASSES> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-highlighter-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-highlighter-5.5.2.jar!/" /> | |||
</CLASSES> | |||
<JAVADOC /> | |||
<SOURCES> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-highlighter-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-highlighter-5.5.2.jar!/" /> | |||
</SOURCES> | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module-library"> | |||
<library name="lucene-memory-4.10.4.jar"> | |||
<library name="lucene-memory-5.5.2.jar"> | |||
<CLASSES> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-memory-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-memory-5.5.2.jar!/" /> | |||
</CLASSES> | |||
<JAVADOC /> | |||
<SOURCES> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-memory-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-memory-5.5.2.jar!/" /> | |||
</SOURCES> | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module-library"> | |||
<library name="lucene-queries-4.10.4.jar"> | |||
<library name="lucene-queries-5.5.2.jar"> | |||
<CLASSES> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-queries-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-queries-5.5.2.jar!/" /> | |||
</CLASSES> | |||
<JAVADOC /> | |||
<SOURCES> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-queries-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-queries-5.5.2.jar!/" /> | |||
</SOURCES> | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module-library"> | |||
<library name="lucene-queryparser-4.10.4.jar"> | |||
<library name="lucene-queryparser-5.5.2.jar"> | |||
<CLASSES> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-queryparser-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-queryparser-5.5.2.jar!/" /> | |||
</CLASSES> | |||
<JAVADOC /> | |||
<SOURCES> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-queryparser-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-queryparser-5.5.2.jar!/" /> | |||
</SOURCES> | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module-library"> | |||
<library name="lucene-sandbox-4.10.4.jar"> | |||
<library name="lucene-sandbox-5.5.2.jar"> | |||
<CLASSES> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-sandbox-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/lucene-sandbox-5.5.2.jar!/" /> | |||
</CLASSES> | |||
<JAVADOC /> | |||
<SOURCES> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-sandbox-4.10.4.jar!/" /> | |||
<root url="jar://$MODULE_DIR$/ext/src/lucene-sandbox-5.5.2.jar!/" /> | |||
</SOURCES> | |||
</library> | |||
</orderEntry> |
@@ -0,0 +1,55 @@ | |||
/* | |||
* Copyright 2017 gitblit.com. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package com.gitblit.service; | |||
import java.io.File; | |||
import com.gitblit.utils.LuceneIndexStore; | |||
/** | |||
* @author Florian Zschocke | |||
* | |||
* @since 1.9.0 | |||
*/ | |||
class LuceneRepoIndexStore extends LuceneIndexStore | |||
{ | |||
private static final String LUCENE_DIR = "lucene"; | |||
private static final String CONF_FILE = "gb_lucene.conf"; | |||
/** | |||
* @param repositoryFolder | |||
* The directory of the repository for this index | |||
* @param indexVersion | |||
* Version of the index definition | |||
*/ | |||
public LuceneRepoIndexStore(File repositoryFolder, int indexVersion) { | |||
super(new File(repositoryFolder, LUCENE_DIR), indexVersion); | |||
} | |||
/** | |||
* Get the index config File. | |||
* | |||
* @return The index config File | |||
*/ | |||
public File getConfigFile() { | |||
return new File(this.indexFolder, CONF_FILE); | |||
} | |||
} |
@@ -65,7 +65,6 @@ import org.apache.lucene.search.highlight.SimpleHTMLFormatter; | |||
import org.apache.lucene.search.highlight.SimpleSpanFragmenter; | |||
import org.apache.lucene.store.Directory; | |||
import org.apache.lucene.store.FSDirectory; | |||
import org.apache.lucene.util.Version; | |||
import org.eclipse.jgit.diff.DiffEntry.ChangeType; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.FileMode; | |||
@@ -118,15 +117,9 @@ public class LuceneService implements Runnable { | |||
private static final String FIELD_DATE = "date"; | |||
private static final String FIELD_TAG = "tag"; | |||
private static final String CONF_FILE = "lucene.conf"; | |||
private static final String LUCENE_DIR = "lucene"; | |||
private static final String CONF_INDEX = "index"; | |||
private static final String CONF_VERSION = "version"; | |||
private static final String CONF_ALIAS = "aliases"; | |||
private static final String CONF_BRANCH = "branches"; | |||
private static final Version LUCENE_VERSION = Version.LUCENE_4_10_0; | |||
private final Logger logger = LoggerFactory.getLogger(LuceneService.class); | |||
private final IStoredSettings storedSettings; | |||
@@ -267,7 +260,7 @@ public class LuceneService implements Runnable { | |||
// close all writers | |||
for (String writer : writers.keySet()) { | |||
try { | |||
writers.get(writer).close(true); | |||
writers.get(writer).close(); | |||
} catch (Throwable t) { | |||
logger.error("Failed to close Lucene writer for " + writer, t); | |||
} | |||
@@ -293,26 +286,13 @@ public class LuceneService implements Runnable { | |||
* @return true, if successful | |||
*/ | |||
public boolean deleteIndex(String repositoryName) { | |||
try { | |||
// close any open writer/searcher | |||
close(repositoryName); | |||
// delete the index folder | |||
File repositoryFolder = FileKey.resolve(new File(repositoriesFolder, repositoryName), FS.DETECTED); | |||
File luceneIndex = new File(repositoryFolder, LUCENE_DIR); | |||
if (luceneIndex.exists()) { | |||
org.eclipse.jgit.util.FileUtils.delete(luceneIndex, | |||
org.eclipse.jgit.util.FileUtils.RECURSIVE); | |||
} | |||
// delete the config file | |||
File luceneConfig = new File(repositoryFolder, CONF_FILE); | |||
if (luceneConfig.exists()) { | |||
luceneConfig.delete(); | |||
} | |||
return true; | |||
} catch (IOException e) { | |||
throw new RuntimeException(e); | |||
} | |||
// close any open writer/searcher | |||
close(repositoryName); | |||
// delete the index folder | |||
File repositoryFolder = FileKey.resolve(new File(repositoriesFolder, repositoryName), FS.DETECTED); | |||
LuceneRepoIndexStore luceneIndex = new LuceneRepoIndexStore(repositoryFolder, INDEX_VERSION); | |||
return luceneIndex.delete(); | |||
} | |||
/** | |||
@@ -386,29 +366,20 @@ public class LuceneService implements Runnable { | |||
* @return a config object | |||
*/ | |||
private FileBasedConfig getConfig(Repository repository) { | |||
File file = new File(repository.getDirectory(), CONF_FILE); | |||
FileBasedConfig config = new FileBasedConfig(file, FS.detect()); | |||
LuceneRepoIndexStore luceneIndex = new LuceneRepoIndexStore(repository.getDirectory(), INDEX_VERSION); | |||
FileBasedConfig config = new FileBasedConfig(luceneIndex.getConfigFile(), FS.detect()); | |||
return config; | |||
} | |||
/** | |||
* Reads the Lucene config file for the repository to check the index | |||
* version. If the index version is different, then rebuild the repository | |||
* index. | |||
* Checks if an index exists for the repository, that is compatible with | |||
* INDEX_VERSION and the Lucene version. | |||
* | |||
* @param repository | |||
* @return true of the on-disk index format is different than INDEX_VERSION | |||
* @return true if no index is found for the repository, false otherwise. | |||
*/ | |||
private boolean shouldReindex(Repository repository) { | |||
try { | |||
FileBasedConfig config = getConfig(repository); | |||
config.load(); | |||
int indexVersion = config.getInt(CONF_INDEX, CONF_VERSION, 0); | |||
// reindex if versions do not match | |||
return indexVersion != INDEX_VERSION; | |||
} catch (Throwable t) { | |||
} | |||
return true; | |||
return ! (new LuceneRepoIndexStore(repository.getDirectory(), INDEX_VERSION).hasIndex()); | |||
} | |||
@@ -618,7 +589,6 @@ public class LuceneService implements Runnable { | |||
reader.close(); | |||
// commit all changes and reset the searcher | |||
config.setInt(CONF_INDEX, null, CONF_VERSION, INDEX_VERSION); | |||
config.save(); | |||
writer.commit(); | |||
resetIndexSearcher(model.name); | |||
@@ -721,10 +691,9 @@ public class LuceneService implements Runnable { | |||
String pattern = MessageFormat.format("{0}:'{'0} AND {1}:\"'{'1'}'\" AND {2}:\"'{'2'}'\"", FIELD_OBJECT_TYPE, FIELD_BRANCH, FIELD_PATH); | |||
String q = MessageFormat.format(pattern, SearchObjectType.blob.name(), branch, path); | |||
BooleanQuery query = new BooleanQuery(); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(LUCENE_VERSION); | |||
QueryParser qp = new QueryParser(LUCENE_VERSION, FIELD_SUMMARY, analyzer); | |||
query.add(qp.parse(q), Occur.MUST); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(); | |||
QueryParser qp = new QueryParser(FIELD_SUMMARY, analyzer); | |||
BooleanQuery query = new BooleanQuery.Builder().add(qp.parse(q), Occur.MUST).build(); | |||
IndexWriter writer = getIndexWriter(repositoryName); | |||
int numDocsBefore = writer.numDocs(); | |||
@@ -848,7 +817,6 @@ public class LuceneService implements Runnable { | |||
} | |||
// update the config | |||
config.setInt(CONF_INDEX, null, CONF_VERSION, INDEX_VERSION); | |||
config.setString(CONF_ALIAS, null, keyName, branchName); | |||
config.setString(CONF_BRANCH, null, keyName, branch.getObjectId().getName()); | |||
config.save(); | |||
@@ -966,16 +934,13 @@ public class LuceneService implements Runnable { | |||
*/ | |||
private IndexWriter getIndexWriter(String repository) throws IOException { | |||
IndexWriter indexWriter = writers.get(repository); | |||
File repositoryFolder = FileKey.resolve(new File(repositoriesFolder, repository), FS.DETECTED); | |||
File indexFolder = new File(repositoryFolder, LUCENE_DIR); | |||
Directory directory = FSDirectory.open(indexFolder); | |||
if (indexWriter == null) { | |||
if (!indexFolder.exists()) { | |||
indexFolder.mkdirs(); | |||
} | |||
StandardAnalyzer analyzer = new StandardAnalyzer(LUCENE_VERSION); | |||
IndexWriterConfig config = new IndexWriterConfig(LUCENE_VERSION, analyzer); | |||
File repositoryFolder = FileKey.resolve(new File(repositoriesFolder, repository), FS.DETECTED); | |||
LuceneRepoIndexStore indexStore = new LuceneRepoIndexStore(repositoryFolder, INDEX_VERSION); | |||
indexStore.create(); | |||
Directory directory = FSDirectory.open(indexStore.getPath()); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(); | |||
IndexWriterConfig config = new IndexWriterConfig(analyzer); | |||
config.setOpenMode(OpenMode.CREATE_OR_APPEND); | |||
indexWriter = new IndexWriter(directory, config); | |||
writers.put(repository, indexWriter); | |||
@@ -1028,18 +993,18 @@ public class LuceneService implements Runnable { | |||
return null; | |||
} | |||
Set<SearchResult> results = new LinkedHashSet<SearchResult>(); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(LUCENE_VERSION); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(); | |||
try { | |||
// default search checks summary and content | |||
BooleanQuery query = new BooleanQuery(); | |||
BooleanQuery.Builder bldr = new BooleanQuery.Builder(); | |||
QueryParser qp; | |||
qp = new QueryParser(LUCENE_VERSION, FIELD_SUMMARY, analyzer); | |||
qp = new QueryParser(FIELD_SUMMARY, analyzer); | |||
qp.setAllowLeadingWildcard(true); | |||
query.add(qp.parse(text), Occur.SHOULD); | |||
bldr.add(qp.parse(text), Occur.SHOULD); | |||
qp = new QueryParser(LUCENE_VERSION, FIELD_CONTENT, analyzer); | |||
qp = new QueryParser(FIELD_CONTENT, analyzer); | |||
qp.setAllowLeadingWildcard(true); | |||
query.add(qp.parse(text), Occur.SHOULD); | |||
bldr.add(qp.parse(text), Occur.SHOULD); | |||
IndexSearcher searcher; | |||
if (repositories.length == 1) { | |||
@@ -1057,10 +1022,11 @@ public class LuceneService implements Runnable { | |||
searcher = new IndexSearcher(reader); | |||
} | |||
BooleanQuery query = bldr.build(); | |||
Query rewrittenQuery = searcher.rewrite(query); | |||
logger.debug(rewrittenQuery.toString()); | |||
TopScoreDocCollector collector = TopScoreDocCollector.create(5000, true); | |||
TopScoreDocCollector collector = TopScoreDocCollector.create(5000); | |||
searcher.search(rewrittenQuery, collector); | |||
int offset = Math.max(0, (page - 1) * pageSize); | |||
ScoreDoc[] hits = collector.topDocs(offset, pageSize).scoreDocs; | |||
@@ -1225,7 +1191,7 @@ public class LuceneService implements Runnable { | |||
*/ | |||
private class MultiSourceReader extends MultiReader { | |||
MultiSourceReader(IndexReader [] readers) { | |||
MultiSourceReader(IndexReader [] readers) throws IOException { | |||
super(readers, false); | |||
} | |||
@@ -110,9 +110,8 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi | |||
} | |||
@Override | |||
public BranchTicketService start() { | |||
public void onStart() { | |||
log.info("{} started", getClass().getSimpleName()); | |||
return this; | |||
} | |||
@Override |
@@ -80,9 +80,8 @@ public class FileTicketService extends ITicketService { | |||
} | |||
@Override | |||
public FileTicketService start() { | |||
public void onStart() { | |||
log.info("{} started", getClass().getSimpleName()); | |||
return this; | |||
} | |||
@Override |
@@ -181,7 +181,24 @@ public abstract class ITicketService implements IManager { | |||
* @since 1.4.0 | |||
*/ | |||
@Override | |||
public abstract ITicketService start(); | |||
public final ITicketService start() { | |||
onStart(); | |||
if (shouldReindex()) { | |||
log.info("Re-indexing all tickets..."); | |||
// long startTime = System.currentTimeMillis(); | |||
reindex(); | |||
// float duration = (System.currentTimeMillis() - startTime) / 1000f; | |||
// log.info("Built Lucene index over all tickets in {} secs", duration); | |||
} | |||
return this; | |||
} | |||
/** | |||
* Start the specific ticket service implementation. | |||
* | |||
* @since 1.9.0 | |||
*/ | |||
public abstract void onStart(); | |||
/** | |||
* Stop the service. | |||
@@ -196,6 +213,12 @@ public abstract class ITicketService implements IManager { | |||
return this; | |||
} | |||
/** | |||
* Closes any open resources used by this service. | |||
* @since 1.4.0 | |||
*/ | |||
protected abstract void close(); | |||
/** | |||
* Creates a ticket notifier. The ticket notifier is not thread-safe! | |||
* @since 1.4.0 | |||
@@ -273,12 +296,6 @@ public abstract class ITicketService implements IManager { | |||
return indexer.hasTickets(repository); | |||
} | |||
/** | |||
* Closes any open resources used by this service. | |||
* @since 1.4.0 | |||
*/ | |||
protected abstract void close(); | |||
/** | |||
* Reset all caches in the service. | |||
* @since 1.4.0 | |||
@@ -1343,6 +1360,18 @@ public abstract class ITicketService implements IManager { | |||
return indexer.queryFor(query, page, pageSize, sortBy, descending); | |||
} | |||
/** | |||
* Checks tickets should get re-indexed. | |||
* | |||
* @return true if tickets should get re-indexed, false otherwise. | |||
*/ | |||
private boolean shouldReindex() | |||
{ | |||
return indexer.shouldReindex(); | |||
} | |||
/** | |||
* Destroys an existing index and reindexes all tickets. | |||
* This operation may be expensive and time-consuming. |
@@ -61,9 +61,8 @@ public class NullTicketService extends ITicketService { | |||
} | |||
@Override | |||
public NullTicketService start() { | |||
public void onStart() { | |||
log.info("{} started", getClass().getSimpleName()); | |||
return this; | |||
} | |||
@Override |
@@ -83,12 +83,11 @@ public class RedisTicketService extends ITicketService { | |||
} | |||
@Override | |||
public RedisTicketService start() { | |||
public void onStart() { | |||
log.info("{} started", getClass().getSimpleName()); | |||
if (!isReady()) { | |||
log.warn("{} is not ready!", getClass().getSimpleName()); | |||
} | |||
return this; | |||
} | |||
@Override |
@@ -31,6 +31,8 @@ import org.apache.lucene.document.Document; | |||
import org.apache.lucene.document.Field.Store; | |||
import org.apache.lucene.document.IntField; | |||
import org.apache.lucene.document.LongField; | |||
import org.apache.lucene.document.NumericDocValuesField; | |||
import org.apache.lucene.document.SortedDocValuesField; | |||
import org.apache.lucene.document.TextField; | |||
import org.apache.lucene.index.DirectoryReader; | |||
import org.apache.lucene.index.IndexWriter; | |||
@@ -49,7 +51,7 @@ import org.apache.lucene.search.TopFieldDocs; | |||
import org.apache.lucene.search.TopScoreDocCollector; | |||
import org.apache.lucene.store.Directory; | |||
import org.apache.lucene.store.FSDirectory; | |||
import org.apache.lucene.util.Version; | |||
import org.apache.lucene.util.BytesRef; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
@@ -60,7 +62,7 @@ import com.gitblit.models.TicketModel; | |||
import com.gitblit.models.TicketModel.Attachment; | |||
import com.gitblit.models.TicketModel.Patchset; | |||
import com.gitblit.models.TicketModel.Status; | |||
import com.gitblit.utils.FileUtils; | |||
import com.gitblit.utils.LuceneIndexStore; | |||
import com.gitblit.utils.StringUtils; | |||
/** | |||
@@ -108,6 +110,8 @@ public class TicketIndexer { | |||
priority(Type.INT), | |||
severity(Type.INT); | |||
final static int INDEX_VERSION = 2; | |||
final Type fieldType; | |||
Lucene(Type fieldType) { | |||
@@ -167,16 +171,15 @@ public class TicketIndexer { | |||
private final Logger log = LoggerFactory.getLogger(getClass()); | |||
private final Version luceneVersion = Version.LUCENE_46; | |||
private final File luceneDir; | |||
private final LuceneIndexStore indexStore; | |||
private IndexWriter writer; | |||
private IndexSearcher searcher; | |||
public TicketIndexer(IRuntimeManager runtimeManager) { | |||
this.luceneDir = runtimeManager.getFileOrFolder(Keys.tickets.indexFolder, "${baseFolder}/tickets/lucene"); | |||
File luceneDir = runtimeManager.getFileOrFolder(Keys.tickets.indexFolder, "${baseFolder}/tickets/lucene"); | |||
this.indexStore = new LuceneIndexStore(luceneDir, Lucene.INDEX_VERSION); | |||
} | |||
/** | |||
@@ -192,7 +195,7 @@ public class TicketIndexer { | |||
*/ | |||
public void deleteAll() { | |||
close(); | |||
FileUtils.delete(luceneDir); | |||
indexStore.delete(); | |||
} | |||
/** | |||
@@ -201,10 +204,9 @@ public class TicketIndexer { | |||
public boolean deleteAll(RepositoryModel repository) { | |||
try { | |||
IndexWriter writer = getWriter(); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(luceneVersion); | |||
QueryParser qp = new QueryParser(luceneVersion, Lucene.rid.name(), analyzer); | |||
BooleanQuery query = new BooleanQuery(); | |||
query.add(qp.parse(repository.getRID()), Occur.MUST); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(); | |||
QueryParser qp = new QueryParser(Lucene.rid.name(), analyzer); | |||
BooleanQuery query = new BooleanQuery.Builder().add(qp.parse(repository.getRID()), Occur.MUST).build(); | |||
int numDocsBefore = writer.numDocs(); | |||
writer.deleteDocuments(query); | |||
@@ -224,6 +226,18 @@ public class TicketIndexer { | |||
return false; | |||
} | |||
/** | |||
* Checks if a tickets index exists, that is compatible with Lucene.INDEX_VERSION | |||
* and the Lucene codec version. | |||
* | |||
* @return true if no tickets index is found, false otherwise. | |||
* | |||
* @since 1.9.0 | |||
*/ | |||
boolean shouldReindex() { | |||
return ! this.indexStore.hasIndex(); | |||
} | |||
/** | |||
* Bulk Add/Update tickets in the Lucene index | |||
* | |||
@@ -287,10 +301,9 @@ public class TicketIndexer { | |||
* @return true, if deleted, false if no record was deleted | |||
*/ | |||
private boolean delete(String repository, long ticketId, IndexWriter writer) throws Exception { | |||
StandardAnalyzer analyzer = new StandardAnalyzer(luceneVersion); | |||
QueryParser qp = new QueryParser(luceneVersion, Lucene.did.name(), analyzer); | |||
BooleanQuery query = new BooleanQuery(); | |||
query.add(qp.parse(StringUtils.getSHA1(repository + ticketId)), Occur.MUST); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(); | |||
QueryParser qp = new QueryParser(Lucene.did.name(), analyzer); | |||
BooleanQuery query = new BooleanQuery.Builder().add(qp.parse(StringUtils.getSHA1(repository + ticketId)), Occur.MUST).build(); | |||
int numDocsBefore = writer.numDocs(); | |||
writer.deleteDocuments(query); | |||
@@ -331,30 +344,30 @@ public class TicketIndexer { | |||
return Collections.emptyList(); | |||
} | |||
Set<QueryResult> results = new LinkedHashSet<QueryResult>(); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(luceneVersion); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(); | |||
try { | |||
// search the title, description and content | |||
BooleanQuery query = new BooleanQuery(); | |||
BooleanQuery.Builder bldr = new BooleanQuery.Builder(); | |||
QueryParser qp; | |||
qp = new QueryParser(luceneVersion, Lucene.title.name(), analyzer); | |||
qp = new QueryParser(Lucene.title.name(), analyzer); | |||
qp.setAllowLeadingWildcard(true); | |||
query.add(qp.parse(text), Occur.SHOULD); | |||
bldr.add(qp.parse(text), Occur.SHOULD); | |||
qp = new QueryParser(luceneVersion, Lucene.body.name(), analyzer); | |||
qp = new QueryParser(Lucene.body.name(), analyzer); | |||
qp.setAllowLeadingWildcard(true); | |||
query.add(qp.parse(text), Occur.SHOULD); | |||
bldr.add(qp.parse(text), Occur.SHOULD); | |||
qp = new QueryParser(luceneVersion, Lucene.content.name(), analyzer); | |||
qp = new QueryParser(Lucene.content.name(), analyzer); | |||
qp.setAllowLeadingWildcard(true); | |||
query.add(qp.parse(text), Occur.SHOULD); | |||
bldr.add(qp.parse(text), Occur.SHOULD); | |||
IndexSearcher searcher = getSearcher(); | |||
Query rewrittenQuery = searcher.rewrite(query); | |||
Query rewrittenQuery = searcher.rewrite(bldr.build()); | |||
log.debug(rewrittenQuery.toString()); | |||
TopScoreDocCollector collector = TopScoreDocCollector.create(5000, true); | |||
TopScoreDocCollector collector = TopScoreDocCollector.create(5000); | |||
searcher.search(rewrittenQuery, collector); | |||
int offset = Math.max(0, (page - 1) * pageSize); | |||
ScoreDoc[] hits = collector.topDocs(offset, pageSize).scoreDocs; | |||
@@ -392,9 +405,9 @@ public class TicketIndexer { | |||
} | |||
Set<QueryResult> results = new LinkedHashSet<QueryResult>(); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(luceneVersion); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(); | |||
try { | |||
QueryParser qp = new QueryParser(luceneVersion, Lucene.content.name(), analyzer); | |||
QueryParser qp = new QueryParser(Lucene.content.name(), analyzer); | |||
Query query = qp.parse(queryText); | |||
IndexSearcher searcher = getSearcher(); | |||
@@ -409,7 +422,7 @@ public class TicketIndexer { | |||
sort = new Sort(Lucene.fromString(sortBy).asSortField(desc)); | |||
} | |||
int maxSize = 5000; | |||
TopFieldDocs docs = searcher.search(rewrittenQuery, null, maxSize, sort, false, false); | |||
TopFieldDocs docs = searcher.search(rewrittenQuery, maxSize, sort, false, false); | |||
int size = (pageSize <= 0) ? maxSize : pageSize; | |||
int offset = Math.max(0, (page - 1) * size); | |||
ScoreDoc[] hits = subset(docs.scoreDocs, offset, size); | |||
@@ -443,14 +456,11 @@ public class TicketIndexer { | |||
private IndexWriter getWriter() throws IOException { | |||
if (writer == null) { | |||
Directory directory = FSDirectory.open(luceneDir); | |||
if (!luceneDir.exists()) { | |||
luceneDir.mkdirs(); | |||
} | |||
indexStore.create(); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(luceneVersion); | |||
IndexWriterConfig config = new IndexWriterConfig(luceneVersion, analyzer); | |||
Directory directory = FSDirectory.open(indexStore.getPath()); | |||
StandardAnalyzer analyzer = new StandardAnalyzer(); | |||
IndexWriterConfig config = new IndexWriterConfig(analyzer); | |||
config.setOpenMode(OpenMode.CREATE_OR_APPEND); | |||
writer = new IndexWriter(directory, config); | |||
} | |||
@@ -554,14 +564,17 @@ public class TicketIndexer { | |||
return; | |||
} | |||
doc.add(new LongField(lucene.name(), value.getTime(), Store.YES)); | |||
doc.add(new NumericDocValuesField(lucene.name(), value.getTime())); | |||
} | |||
private void toDocField(Document doc, Lucene lucene, long value) { | |||
doc.add(new LongField(lucene.name(), value, Store.YES)); | |||
doc.add(new NumericDocValuesField(lucene.name(), value)); | |||
} | |||
private void toDocField(Document doc, Lucene lucene, int value) { | |||
doc.add(new IntField(lucene.name(), value, Store.YES)); | |||
doc.add(new NumericDocValuesField(lucene.name(), value)); | |||
} | |||
private void toDocField(Document doc, Lucene lucene, String value) { | |||
@@ -569,6 +582,7 @@ public class TicketIndexer { | |||
return; | |||
} | |||
doc.add(new org.apache.lucene.document.Field(lucene.name(), value, TextField.TYPE_STORED)); | |||
doc.add(new SortedDocValuesField(lucene.name(), new BytesRef(value))); | |||
} | |||
/** | |||
@@ -663,4 +677,4 @@ public class TicketIndexer { | |||
int i = Integer.parseInt(val); | |||
return i; | |||
} | |||
} | |||
} |
@@ -0,0 +1,98 @@ | |||
/* | |||
* Copyright 2017 gitblit.com. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package com.gitblit.utils; | |||
import java.io.File; | |||
import java.nio.file.Path; | |||
/** | |||
* @author Florian Zschocke | |||
* | |||
* @since 1.9.0 | |||
*/ | |||
public class LuceneIndexStore | |||
{ | |||
public static final int LUCENE_CODEC_VERSION = 54; | |||
protected File indexFolder; | |||
/** | |||
* Constructor for a base folder that contains the version specific index folders | |||
* and an index version. | |||
* | |||
* @param luceneFolder | |||
* Path to the base folder for the Lucene indices, i.e. the common "lucene" directory. | |||
* @param indexVersion | |||
* Version of the index definition | |||
*/ | |||
public LuceneIndexStore(File luceneFolder, int indexVersion) | |||
{ | |||
this.indexFolder = new File(luceneFolder, indexVersion + "_" + LUCENE_CODEC_VERSION); | |||
} | |||
/** | |||
* Create the Lucene index directory for this index version and Lucene codec version | |||
*/ | |||
public void create() | |||
{ | |||
if (! indexFolder.exists()) { | |||
indexFolder.mkdirs(); | |||
} | |||
} | |||
/** | |||
* Delete the Lucene index directory for this index version and Lucene codec version | |||
* | |||
* @return True if the directory could successfully be deleted. | |||
*/ | |||
public boolean delete() | |||
{ | |||
if (indexFolder.exists()) { | |||
return FileUtils.delete(indexFolder); | |||
} | |||
return true; | |||
} | |||
/** | |||
* @return The Path to the index folder | |||
*/ | |||
public Path getPath() | |||
{ | |||
return indexFolder.toPath(); | |||
} | |||
/** | |||
* Check if an index of the respective version, or compatible, already exists. | |||
* | |||
* @return True if an index exists, False otherwise | |||
*/ | |||
public boolean hasIndex() | |||
{ | |||
return indexFolder.exists() && | |||
indexFolder.isDirectory() && | |||
(indexFolder.list().length > 1); // Must have more than 'write.lock' | |||
} | |||
} |
@@ -218,7 +218,8 @@ gb.pages = pages | |||
gb.workingCopy = working copy | |||
gb.workingCopyWarning = this repository has a working copy and can not receive pushes | |||
gb.query = query | |||
gb.queryHelp = Standard query syntax is supported.<p/><p/>Please see <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> for details. | |||
gb.queryHelp = Standard query syntax is supported.<p/><p/>Please see ${querySyntax} for details. | |||
gb.querySyntax = Lucene Query Parser Syntax | |||
gb.queryResults = results {0} - {1} ({2} hits) | |||
gb.noHits = no hits | |||
gb.authored = authored |
@@ -773,7 +773,8 @@ gb.transportPreferenceDescription=Vyberte transport, kter\u00fd preferujete pro | |||
gb.sortHighestSeverity=nejvy\u0161\u0161\u00ed z\u00e1va\u017enost | |||
gb.diffFileDiffTooLarge=Rozd\u00edl je p\u0159\u00edli\u0161 velk\u00fd | |||
gb.missingIntegrationBranchMore=C\u00edlov\u00e1 integra\u010dn\u00ed v\u011btev v repozit\u00e1\u0159i neexistuje! | |||
gb.queryHelp=Standardn\u00ed syntaxe dotaz\u016f je podporov\u00e1na.<p/><p/>Pod\u00edvejte se pros\u00edm na <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> pro detaily. | |||
gb.queryHelp=Standardn\u00ed syntaxe dotaz\u016f je podporov\u00e1na.<p/><p/>Pod\u00edvejte se pros\u00edm na ${querySyntax} pro detaily. | |||
gb.querySyntax=Lucene Query Parser Syntax | |||
gb.diffTruncated=Diff o\u0159iznut po p\u0159edchoz\u00edm souboru | |||
gb.blame=blame | |||
gb.imgdiffSubtract=Od\u010d\u00edtat (\u010dern\u00e1 = stejn\u00e9l) |
@@ -218,7 +218,8 @@ gb.pages = Seiten | |||
gb.workingCopy = Arbeitskopie | |||
gb.workingCopyWarning = Dieses Repository besitzt eine Arbeitskopie und kann keine Pushes empfangen | |||
gb.query = Abfrage | |||
gb.queryHelp = Standard Abfragesyntax wird unterst\u00fctzt.<p/><p/>Unter <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> finden Sie weitere Details. | |||
gb.queryHelp = Standard Abfragesyntax wird unterst\u00fctzt.<p/><p/>Unter ${querySyntax} finden Sie weitere Details. | |||
gb.querySyntax = Lucene Query Parser Syntax | |||
gb.queryResults = Ergebnisse {0} - {1} ({2} Treffer) | |||
gb.noHits = Keine Treffer | |||
gb.authored = ist Autor von |
@@ -218,7 +218,8 @@ gb.pages = P\u00E1ginas | |||
gb.workingCopy = Copia de trabajo | |||
gb.workingCopyWarning = Este repositorio tiene una copia de trabajo y no se le puede empujar | |||
gb.query = Consulta | |||
gb.queryHelp = Se admite la sintaxis de consulta est\u00E1ndar.<p/>Por favor, lee el: <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Analizador sint\u00E1ctico de consultas de Lucene</a> para m\u00E1s detalles. | |||
gb.queryHelp = Se admite la sintaxis de consulta est\u00E1ndar.<p/>Por favor, lee el: ${querySyntax} para m\u00E1s detalles. | |||
gb.querySyntax = Analizador sint\u00E1ctico de consultas de Lucene | |||
gb.queryResults = Resultados {0} - {1} ({2} coincidencias) | |||
gb.noHits = Sin coincidencias | |||
gb.authored = Autor |
@@ -218,7 +218,8 @@ gb.pages = pages | |||
gb.workingCopy = d\u00e9p\u00f4t de travail | |||
gb.workingCopyWarning = ce d\u00e9p\u00f4t poss\u00e8de un d\u00e9p\u00f4t de travail et ne peut donc pas recevoir de pushes | |||
gb.query = recherche | |||
gb.queryHelp = La syntaxe Lucene standard est support\u00e9e.<p/><p/>Se r\u00e9f\u00e9rer \u00e0 la <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Syntaxe de recherche Lucene</a> pour plus de d\u00e9tails. | |||
gb.queryHelp = La syntaxe Lucene standard est support\u00e9e.<p/><p/>Se r\u00e9f\u00e9rer \u00e0 la ${querySyntax} pour plus de d\u00e9tails. | |||
gb.querySyntax = Syntaxe de recherche Lucene | |||
gb.queryResults = r\u00e9sultats {0} - {1} ({2} hits) | |||
gb.noHits = aucun r\u00e9sultats | |||
gb.authored = authored |
@@ -218,7 +218,8 @@ gb.pages = pagine | |||
gb.workingCopy = copia di lavoro | |||
gb.workingCopyWarning = questo repository è una copia di lavoro a non ammette push | |||
gb.query = interrogazione | |||
gb.queryHelp = La sintassi standard è supportata.<p/><p/>Si vedi <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> per ulteriori dettagli. | |||
gb.queryHelp = La sintassi standard è supportata.<p/><p/>Si vedi ${querySyntax} per ulteriori dettagli. | |||
gb.querySyntax = Lucene Query Parser Syntax | |||
gb.queryResults = risultati {0} - {1} ({2} corrispondenze) | |||
gb.noHits = nessuna corrispondenza | |||
gb.authored = creato da |
@@ -217,7 +217,8 @@ gb.pages = \u30da\u30fc\u30b8 | |||
gb.workingCopy = \u4f5c\u696d\u30b3\u30d4\u30fc | |||
gb.workingCopyWarning = \u3053\u306e\u30ea\u30dd\u30b8\u30c8\u30ea\u306b\u306f\u4f5c\u696d\u30b3\u30d4\u30fc\u304c\u3042\u308b\u305f\u3081 push \u3067\u304d\u307e\u305b\u3093 | |||
gb.query = \u30af\u30a8\u30ea\u30fc | |||
gb.queryHelp = \u6a19\u6e96\u7684\u306a\u30af\u30a8\u30ea\u30fc\u66f8\u5f0f\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u3059\u3002<p/><p/>\u8a73\u7d30\u306f <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> \u3092\u53c2\u7167\u3057\u3066\u4e0b\u3055\u3044\u3002 | |||
gb.queryHelp = \u6a19\u6e96\u7684\u306a\u30af\u30a8\u30ea\u30fc\u66f8\u5f0f\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u3059\u3002<p/><p/>\u8a73\u7d30\u306f ${querySyntax} \u3092\u53c2\u7167\u3057\u3066\u4e0b\u3055\u3044\u3002 | |||
gb.querySyntax = Lucene Query Parser Syntax | |||
gb.queryResults = \u691c\u7d22\u7d50\u679c {0} - {1} ({2} \u30d2\u30c3\u30c8) | |||
gb.noHits = \u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002 | |||
gb.authored = authored |
@@ -180,110 +180,111 @@ gb.free = \uD504\uB9AC | |||
gb.version = \uBC84\uC804 | |||
gb.releaseDate = \uB9B4\uB9AC\uC988 \uB0A0\uC9DC | |||
gb.date = date | |||
gb.activity = \uC561\uD2F0\uBE44\uD2F0 | |||
gb.subscribe = \uAD6C\uB3C5 | |||
gb.branch = \uBE0C\uB79C\uCE58 | |||
gb.maxHits = \uB9E5\uC2A4\uD788\uD2B8 | |||
gb.recentActivity = \uCD5C\uADFC \uC561\uD2F0\uBE44\uD2F0 | |||
gb.recentActivityStats = \uC9C0\uB09C {0}\uC77C / \uC791\uC131\uC790 {2}\uBA85\uC774 {1}\uAC1C \uCEE4\uBC0B\uD568 | |||
gb.recentActivityNone = \uC9C0\uB09C {0}\uC77C / \uC5C6\uC74C | |||
gb.dailyActivity = \uC77C\uC77C \uC561\uD2F0\uBE44\uD2F0 | |||
gb.activeRepositories = \uC0AC\uC6A9\uC911\uC778 \uC800\uC7A5\uC18C | |||
gb.activeAuthors = \uC0AC\uC6A9\uC911\uC778 \uC791\uC131\uC790 | |||
gb.commits = \uCEE4\uBC0B | |||
gb.teams = \uD300 | |||
gb.teamName = \uD300 \uC774\uB984 | |||
gb.teamMembers = \uD300 \uBA64\uBC84 | |||
gb.teamMemberships = \uD300 \uB9F4\uBC84\uC27D | |||
gb.newTeam = \uC0C8\uB85C\uC6B4 \uD300 | |||
gb.permittedTeams = \uD5C8\uC6A9\uB41C \uD300 | |||
gb.emptyRepository = \uBE48 \uC800\uC7A5\uC18C | |||
gb.repositoryUrl = \uC800\uC7A5\uC18C url | |||
gb.mailingLists = \uBA54\uC77C\uB9C1 \uB9AC\uC2A4\uD2B8 | |||
gb.preReceiveScripts = pre-receive \uC2A4\uD06C\uB9BD\uD2B8 | |||
gb.postReceiveScripts = post-receive \uC2A4\uD06C\uB9BD\uD2B8 | |||
gb.hookScripts = \uD6C4\uD06C \uC2A4\uD06C\uB9BD\uD2B8 | |||
gb.customFields = \uC0AC\uC6A9\uC790 \uD544\uB4DC | |||
gb.customFieldsDescription = \uADF8\uB8E8\uBE44 \uD6C5\uC5D0 \uC0AC\uC6A9\uC790 \uD544\uB4DC \uC0AC\uC6A9 \uAC00\uB2A5 | |||
gb.accessPermissions = \uC811\uC18D \uAD8C\uD55C | |||
gb.filters = \uD544\uD130 | |||
gb.generalDescription = \uC77C\uBC18 \uC124\uC815 | |||
gb.accessPermissionsDescription = \uC720\uC800\uC640 \uD300\uC73C\uB85C \uC811\uC18D\uAD8C\uD55C \uBD80\uC5EC | |||
gb.accessPermissionsForUserDescription = \uD300\uC744 \uC9C0\uC815\uD558\uAC70\uB098 \uC811\uC18D \uAD8C\uD55C\uC744 \uC9C0\uC815\uD560 \uC800\uC7A5\uC18C \uC120\uD0DD | |||
gb.accessPermissionsForTeamDescription = \uD300 \uB9F4\uBC84\uB97C \uC120\uD0DD\uD558\uACE0, \uC811\uC18D \uAD8C\uD55C\uC744 \uC9C0\uC815\uD560 \uC800\uC7A5\uC18C \uC120\uD0DD | |||
gb.federationRepositoryDescription = \uC774 \uC800\uC7A5\uC18C\uB97C \uB2E4\uB978 Gitblit \uC11C\uBC84\uC640 \uACF5\uC720 | |||
gb.hookScriptsDescription = \uC774 Gitblit \uC11C\uBC84\uC5D0 \uD478\uC2DC\uB418\uBA74 \uADF8\uB8E8\uBE44(Groovy) \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC2E4\uD589 | |||
gb.reset = \uB9AC\uC14B | |||
gb.pages = \uD398\uC774\uC9C0 | |||
gb.workingCopy = \uC6CC\uD0B9 \uCE74\uD53C | |||
gb.workingCopyWarning = \uC774 \uC800\uC7A5\uC18C\uB294 \uC6CC\uD0B9\uCE74\uD53C\uB97C \uAC00\uC9C0\uACE0 \uC788\uACE0 \uD478\uC2DC\uB97C \uBC1B\uC744 \uC218 \uC5C6\uC74C | |||
gb.query = \uCFFC\uB9AC | |||
gb.queryHelp = \uD45C\uC900 \uCFFC\uB9AC \uBB38\uBC95\uC744 \uC9C0\uC6D0.<p/><p/>\uC790\uC138\uD55C \uAC83\uC744 \uC6D0\uD55C\uB2E4\uBA74 <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">\uB8E8\uC2E0 \uCFFC\uB9AC \uD30C\uC11C \uBB38\uBC95</a> \uC744 \uBC29\uBB38\uD574 \uC8FC\uC138\uC694. | |||
gb.queryResults = \uAC80\uC0C9\uACB0\uACFC {0} - {1} ({2}\uAC1C \uAC80\uC0C9\uB428) | |||
gb.noHits = \uAC80\uC0C9 \uACB0\uACFC \uC5C6\uC74C | |||
gb.authored = \uAC00 \uC791\uC131\uD568. | |||
gb.committed = \uCEE4\uBC0B\uB428 | |||
gb.indexedBranches = \uC778\uB371\uC2F1\uD560 \uBE0C\uB79C\uCE58 | |||
gb.indexedBranchesDescription = \uB8E8\uC2E0 \uC778\uB371\uC2A4\uC5D0 \uD3EC\uD568\uD560 \uBE0C\uB79C\uCE58 \uC120\uD0DD | |||
gb.noIndexedRepositoriesWarning = \uC800\uC7A5\uC18C\uAC00 \uB8E8\uC2E0 \uC778\uB371\uC2F1\uC5D0 \uC124\uC815\uB418\uC9C0 \uC54A\uC74C | |||
gb.undefinedQueryWarning = \uCFFC\uB9AC \uC9C0\uC815\uB418\uC9C0 \uC54A\uC74C! | |||
gb.noSelectedRepositoriesWarning = \uD558\uB098 \uB610\uB294 \uADF8 \uC774\uC0C1\uC758 \uC800\uC7A5\uC18C\uB97C \uC120\uD0DD\uD558\uC138\uC694! | |||
gb.luceneDisabled = \uB8E8\uC2E0 \uC778\uB371\uC2F1 \uC911\uC9C0\uB428 | |||
gb.failedtoRead = \uC77C\uAE30 \uC2E4\uD328 | |||
gb.isNotValidFile = \uC720\uD6A8\uD55C \uD30C\uC77C\uC774 \uC544\uB2D8 | |||
gb.failedToReadMessage = {0}\uC5D0\uC11C \uB514\uD3F4\uD2B8 \uBA54\uC2DC\uC9C0 \uC77C\uAE30 \uC2E4\uD328! | |||
gb.passwordsDoNotMatch = \uD328\uC2A4\uC6CC\uB4DC\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC544\uC694! | |||
gb.passwordTooShort = \uD328\uC2A4\uC6CC\uB4DC\uAC00 \uB108\uBB34 \uC9E7\uC544\uC694. \uC801\uC5B4\uB3C4 {0} \uAC1C \uBB38\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4. | |||
gb.passwordChanged = \uD328\uC2A4\uC6CC\uB4DC\uAC00 \uBCC0\uACBD \uC131\uACF5. | |||
gb.passwordChangeAborted = \uD328\uC2A4\uC6CC\uB4DC \uBCC0\uACBD \uCDE8\uC18C\uB428. | |||
gb.pleaseSetRepositoryName = \uC800\uC7A5\uC18C \uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694! | |||
gb.illegalLeadingSlash = \uC800\uC7A5\uC18C \uC774\uB984 \uB610\uB294 \uD3F4\uB354\uB294 (/) \uB85C \uC2DC\uC791\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. | |||
gb.illegalRelativeSlash = \uC0C1\uB300 \uACBD\uB85C \uC9C0\uC815 (../) \uC740 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.. | |||
gb.illegalCharacterRepositoryName = \uBB38\uC790 ''{0}'' \uC800\uC7A5\uC18C \uC774\uB984\uC5D0 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC5B4\uC694! | |||
gb.selectAccessRestriction = \uC811\uC18D \uAD8C\uD55C\uC744 \uC120\uD0DD\uD558\uC138\uC694! | |||
gb.selectFederationStrategy = \uD398\uB354\uB808\uC774\uC158 \uC815\uCC45\uC744 \uC120\uD0DD\uD558\uC138\uC694! | |||
gb.pleaseSetTeamName = \uD300\uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694! | |||
gb.teamNameUnavailable = ''{0}'' \uD300\uC740 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC5B4\uC694. | |||
gb.teamMustSpecifyRepository = \uD300\uC740 \uC801\uC5B4\uB3C4 \uD558\uB098\uC758 \uC800\uC7A5\uC18C\uB97C \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4. | |||
gb.teamCreated = \uC0C8\uB85C\uC6B4 \uD300 ''{0}'' \uC0DD\uC131 \uC644\uB8CC. | |||
gb.pleaseSetUsername = \uC720\uC800\uB124\uC784\uC744 \uC785\uB825\uD558\uC138\uC694! | |||
gb.usernameUnavailable = ''{0}'' \uC720\uC800\uB124\uC784\uC740 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC5B4\uC694. | |||
gb.combinedMd5Rename = Gitblit \uC740 combined-md5 \uD574\uC2F1 \uD328\uC2A4\uC6CC\uB4DC\uB85C \uC124\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uACC4\uC815 \uC774\uB984 \uBCC0\uACBD \uC2DC \uC0C8 \uD328\uC2A4\uC6CC\uB4DC\uB97C \uC785\uB825\uD574\uC57C \uD569\uB2C8\uB2E4. | |||
gb.userCreated = \uC0C8\uB85C\uC6B4 \uC720\uC800 ''{0}'' \uC0DD\uC131 \uC644\uB8CC. | |||
gb.couldNotFindFederationRegistration = \uD398\uB354\uB808\uC774\uC158 \uB4F1\uB85D\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4! | |||
gb.failedToFindGravatarProfile = {0} \uC758 Gravatar \uD504\uB85C\uD30C\uC77C \uCC3E\uAE30 \uC2E4\uD328 | |||
gb.branchStats = {2} \uC548\uC5D0 {0} \uCEE4\uBC0B {1} \uD0DC\uADF8 | |||
gb.repositoryNotSpecified = \uC800\uC7A5\uC18C\uAC00 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC74C! | |||
gb.repositoryNotSpecifiedFor = {0} \uB97C \uC704\uD55C \uC800\uC7A5\uC18C\uAC00 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC74C! | |||
gb.canNotLoadRepository = \uC800\uC7A5\uC18C\uB97C \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC74C | |||
gb.commitIsNull = \uB110 \uCEE4\uBC0B | |||
gb.unauthorizedAccessForRepository = \uC800\uC7A5\uC18C\uC5D0 \uC811\uADFC \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uC74C | |||
gb.failedToFindCommit = \uCEE4\uBC0B\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC74C \"{0}\" in {1} for {2} \uD398\uC774\uC9C0! | |||
gb.couldNotFindFederationProposal = \uD398\uB354\uB808\uC774\uC158 \uC81C\uC548\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4! | |||
gb.invalidUsernameOrPassword = \uC798\uBABB\uB41C \uC720\uC800\uB124\uC784 \uB610\uB294 \uD328\uC2A4\uC6CC\uB4DC! | |||
gb.OneProposalToReview = \uAC80\uD1A0\uB97C \uAE30\uB2E4\uB9AC\uACE0 \uC788\uB294 1\uAC1C\uC758 \uD398\uB354\uB808\uC774\uC158 \uC81C\uC548\uC774 \uC788\uC2B5\uB2C8\uB2E4. | |||
gb.nFederationProposalsToReview = \uAC80\uD1A0\uB97C \uAE30\uB2E4\uB9AC\uACE0 \uC788\uB294 {0} \uAC1C\uC758 \uD398\uB354\uB808\uC774\uC158 \uC81C\uC548\uC774 \uC788\uC2B5\uB2C8\uB2E4. | |||
gb.couldNotFindTag = \uD0DC\uADF8 {0} \uB97C(\uC744) \uCC3E\uC744 \uC218 \uC5C6\uC74C | |||
gb.couldNotCreateFederationProposal = \uD398\uB354\uB808\uC774\uC158 \uC81C\uC548 \uC0DD\uC131 \uC2E4\uD328! | |||
gb.pleaseSetGitblitUrl = Gitblit url \uC744 \uC785\uB825\uD558\uC138\uC694! | |||
gb.pleaseSetDestinationUrl = \uB2F9\uC2E0\uC758 \uC81C\uC548\uC5D0 \uB300\uD55C \uB300\uC0C1 url \uC744 \uC785\uB825\uD558\uC138\uC694! | |||
gb.proposalReceived = {0} \uC758 \uC81C\uC548 \uC131\uACF5\uC801 \uC218\uC2E0 | |||
gb.noGitblitFound = \uC8C4\uC1A1\uD569\uB2C8\uB2E4, Gitblit \uC778\uC2A4\uD134\uC2A4 {1} \uC5D0\uC11C {0} \uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. | |||
gb.noProposals = \uC8C4\uC1A1\uD569\uB2C8\uB2E4, \uC774\uBC88\uC5D0\uB294 {0} \uC758 \uC81C\uC548\uC744 \uC218\uC6A9\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. | |||
gb.noFederation = \uC8C4\uC1A1\uD569\uB2C8\uB2E4, {0} \uC5D0\uB294 \uD398\uB354\uB808\uC774\uC158 \uC124\uC815\uB41C Gitblit \uC778\uC2A4\uD134\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. | |||
gb.proposalFailed = \uC8C4\uC1A1\uD569\uB2C8\uB2E4, {0} \uC5D0\uB294 \uC81C\uC548 \uB370\uC774\uD130\uB97C \uBC1B\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. | |||
gb.proposalError = \uC8C4\uC1A1\uD569\uB2C8\uB2E4, {0} \uC5D0 \uB300\uD55C \uC624\uB958 \uBC1C\uC0DD \uBCF4\uACE0 | |||
gb.failedToSendProposal = \uC81C\uC548 \uBCF4\uB0B4\uAE30 \uC2E4\uD328! | |||
gb.userServiceDoesNotPermitAddUser = {0} \uC0C8\uB85C\uC6B4 \uC720\uC800\uB97C \uCD94\uAC00\uD560 \uC218 \uC5C6\uC74C! | |||
gb.userServiceDoesNotPermitPasswordChanges = {0} \uD328\uC2A4\uC6CC\uB4DC\uB97C \uBCC0\uACBD\uD560 \uC218 \uC5C6\uC74C! | |||
gb.displayName = \uD45C\uC2DC\uB418\uB294 \uC774\uB984 | |||
gb.emailAddress = \uC774\uBA54\uC77C \uC8FC\uC18C | |||
gb.errorAdminLoginRequired = \uAD00\uB9AC\uB97C \uC704\uD574\uC11C\uB294 \uB85C\uADF8\uC778\uC774 \uD544\uC694 | |||
gb.errorOnlyAdminMayCreateRepository = \uAD00\uB9AC\uC790\uB9CC \uC800\uC7A5\uC18C\uB97C \uB9CC\uB4E4\uC218 \uC788\uC74C | |||
gb.errorOnlyAdminOrOwnerMayEditRepository = \uAD00\uB9AC\uC790\uC640 \uC18C\uC720\uC790\uB9CC \uC800\uC7A5\uC18C\uB97C \uC218\uC815\uD560 \uC218 \uC788\uC74C | |||
gb.errorAdministrationDisabled = \uAD00\uB9AC\uAE30\uB2A5 \uBE44\uD65C\uC131\uD654\uB428 | |||
gb.lastNDays = {0} \uC77C\uC804 | |||
gb.completeGravatarProfile = Gravatar.com \uC5D0 \uD504\uB85C\uD30C\uC77C \uC0DD\uC131\uB428 | |||
gb.activity = \uc561\ud2f0\ube44\ud2f0 | |||
gb.subscribe = \uad6c\ub3c5 | |||
gb.branch = \ube0c\ub79c\uce58 | |||
gb.maxHits = \ub9e5\uc2a4\ud788\ud2b8 | |||
gb.recentActivity = \ucd5c\uadfc \uc561\ud2f0\ube44\ud2f0 | |||
gb.recentActivityStats = \uc9c0\ub09c {0}\uc77c / \uc791\uc131\uc790 {2}\uba85\uc774 {1}\uac1c \ucee4\ubc0b\ud568 | |||
gb.recentActivityNone = \uc9c0\ub09c {0}\uc77c / \uc5c6\uc74c | |||
gb.dailyActivity = \uc77c\uc77c \uc561\ud2f0\ube44\ud2f0 | |||
gb.activeRepositories = \uc0ac\uc6a9\uc911\uc778 \uc800\uc7a5\uc18c | |||
gb.activeAuthors = \uc0ac\uc6a9\uc911\uc778 \uc791\uc131\uc790 | |||
gb.commits = \ucee4\ubc0b | |||
gb.teams = \ud300 | |||
gb.teamName = \ud300 \uc774\ub984 | |||
gb.teamMembers = \ud300 \uba64\ubc84 | |||
gb.teamMemberships = \ud300 \ub9f4\ubc84\uc27d | |||
gb.newTeam = \uc0c8\ub85c\uc6b4 \ud300 | |||
gb.permittedTeams = \ud5c8\uc6a9\ub41c \ud300 | |||
gb.emptyRepository = \ube48 \uc800\uc7a5\uc18c | |||
gb.repositoryUrl = \uc800\uc7a5\uc18c url | |||
gb.mailingLists = \uba54\uc77c\ub9c1 \ub9ac\uc2a4\ud2b8 | |||
gb.preReceiveScripts = pre-receive \uc2a4\ud06c\ub9bd\ud2b8 | |||
gb.postReceiveScripts = post-receive \uc2a4\ud06c\ub9bd\ud2b8 | |||
gb.hookScripts = \ud6c4\ud06c \uc2a4\ud06c\ub9bd\ud2b8 | |||
gb.customFields = \uc0ac\uc6a9\uc790 \ud544\ub4dc | |||
gb.customFieldsDescription = \uadf8\ub8e8\ube44 \ud6c5\uc5d0 \uc0ac\uc6a9\uc790 \ud544\ub4dc \uc0ac\uc6a9 \uac00\ub2a5 | |||
gb.accessPermissions = \uc811\uc18d \uad8c\ud55c | |||
gb.filters = \ud544\ud130 | |||
gb.generalDescription = \uc77c\ubc18 \uc124\uc815 | |||
gb.accessPermissionsDescription = \uc720\uc800\uc640 \ud300\uc73c\ub85c \uc811\uc18d\uad8c\ud55c \ubd80\uc5ec | |||
gb.accessPermissionsForUserDescription = \ud300\uc744 \uc9c0\uc815\ud558\uac70\ub098 \uc811\uc18d \uad8c\ud55c\uc744 \uc9c0\uc815\ud560 \uc800\uc7a5\uc18c \uc120\ud0dd | |||
gb.accessPermissionsForTeamDescription = \ud300 \ub9f4\ubc84\ub97c \uc120\ud0dd\ud558\uace0, \uc811\uc18d \uad8c\ud55c\uc744 \uc9c0\uc815\ud560 \uc800\uc7a5\uc18c \uc120\ud0dd | |||
gb.federationRepositoryDescription = \uc774 \uc800\uc7a5\uc18c\ub97c \ub2e4\ub978 Gitblit \uc11c\ubc84\uc640 \uacf5\uc720 | |||
gb.hookScriptsDescription = \uc774 Gitblit \uc11c\ubc84\uc5d0 \ud478\uc2dc\ub418\uba74 \uadf8\ub8e8\ube44(Groovy) \uc2a4\ud06c\ub9bd\ud2b8\ub97c \uc2e4\ud589 | |||
gb.reset = \ub9ac\uc14b | |||
gb.pages = \ud398\uc774\uc9c0 | |||
gb.workingCopy = \uc6cc\ud0b9 \uce74\ud53c | |||
gb.workingCopyWarning = \uc774 \uc800\uc7a5\uc18c\ub294 \uc6cc\ud0b9\uce74\ud53c\ub97c \uac00\uc9c0\uace0 \uc788\uace0 \ud478\uc2dc\ub97c \ubc1b\uc744 \uc218 \uc5c6\uc74c | |||
gb.query = \ucffc\ub9ac | |||
gb.queryHelp = \ud45c\uc900 \ucffc\ub9ac \ubb38\ubc95\uc744 \uc9c0\uc6d0.<p/><p/>\uc790\uc138\ud55c \uac83\uc744 \uc6d0\ud55c\ub2e4\uba74 ${querySyntax} \uc744 \ubc29\ubb38\ud574 \uc8fc\uc138\uc694. | |||
gb.querySyntax = \ub8e8\uc2e0 \ucffc\ub9ac \ud30c\uc11c \ubb38\ubc95 | |||
gb.queryResults = \uac80\uc0c9\uacb0\uacfc {0} - {1} ({2}\uac1c \uac80\uc0c9\ub428) | |||
gb.noHits = \uac80\uc0c9 \uacb0\uacfc \uc5c6\uc74c | |||
gb.authored = \uac00 \uc791\uc131\ud568. | |||
gb.committed = \ucee4\ubc0b\ub428 | |||
gb.indexedBranches = \uc778\ub371\uc2f1\ud560 \ube0c\ub79c\uce58 | |||
gb.indexedBranchesDescription = \ub8e8\uc2e0 \uc778\ub371\uc2a4\uc5d0 \ud3ec\ud568\ud560 \ube0c\ub79c\uce58 \uc120\ud0dd | |||
gb.noIndexedRepositoriesWarning = \uc800\uc7a5\uc18c\uac00 \ub8e8\uc2e0 \uc778\ub371\uc2f1\uc5d0 \uc124\uc815\ub418\uc9c0 \uc54a\uc74c | |||
gb.undefinedQueryWarning = \ucffc\ub9ac \uc9c0\uc815\ub418\uc9c0 \uc54a\uc74c! | |||
gb.noSelectedRepositoriesWarning = \ud558\ub098 \ub610\ub294 \uadf8 \uc774\uc0c1\uc758 \uc800\uc7a5\uc18c\ub97c \uc120\ud0dd\ud558\uc138\uc694! | |||
gb.luceneDisabled = \ub8e8\uc2e0 \uc778\ub371\uc2f1 \uc911\uc9c0\ub428 | |||
gb.failedtoRead = \uc77c\uae30 \uc2e4\ud328 | |||
gb.isNotValidFile = \uc720\ud6a8\ud55c \ud30c\uc77c\uc774 \uc544\ub2d8 | |||
gb.failedToReadMessage = {0}\uc5d0\uc11c \ub514\ud3f4\ud2b8 \uba54\uc2dc\uc9c0 \uc77c\uae30 \uc2e4\ud328! | |||
gb.passwordsDoNotMatch = \ud328\uc2a4\uc6cc\ub4dc\uac00 \uc77c\uce58\ud558\uc9c0 \uc54a\uc544\uc694! | |||
gb.passwordTooShort = \ud328\uc2a4\uc6cc\ub4dc\uac00 \ub108\ubb34 \uc9e7\uc544\uc694. \uc801\uc5b4\ub3c4 {0} \uac1c \ubb38\uc790\uc5ec\uc57c \ud569\ub2c8\ub2e4. | |||
gb.passwordChanged = \ud328\uc2a4\uc6cc\ub4dc\uac00 \ubcc0\uacbd \uc131\uacf5. | |||
gb.passwordChangeAborted = \ud328\uc2a4\uc6cc\ub4dc \ubcc0\uacbd \ucde8\uc18c\ub428. | |||
gb.pleaseSetRepositoryName = \uc800\uc7a5\uc18c \uc774\ub984\uc744 \uc785\ub825\ud558\uc138\uc694! | |||
gb.illegalLeadingSlash = \uc800\uc7a5\uc18c \uc774\ub984 \ub610\ub294 \ud3f4\ub354\ub294 (/) \ub85c \uc2dc\uc791\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. | |||
gb.illegalRelativeSlash = \uc0c1\ub300 \uacbd\ub85c \uc9c0\uc815 (../) \uc740 \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.. | |||
gb.illegalCharacterRepositoryName = \ubb38\uc790 ''{0}'' \uc800\uc7a5\uc18c \uc774\ub984\uc5d0 \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc5b4\uc694! | |||
gb.selectAccessRestriction = \uc811\uc18d \uad8c\ud55c\uc744 \uc120\ud0dd\ud558\uc138\uc694! | |||
gb.selectFederationStrategy = \ud398\ub354\ub808\uc774\uc158 \uc815\ucc45\uc744 \uc120\ud0dd\ud558\uc138\uc694! | |||
gb.pleaseSetTeamName = \ud300\uc774\ub984\uc744 \uc785\ub825\ud558\uc138\uc694! | |||
gb.teamNameUnavailable = ''{0}'' \ud300\uc740 \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc5b4\uc694. | |||
gb.teamMustSpecifyRepository = \ud300\uc740 \uc801\uc5b4\ub3c4 \ud558\ub098\uc758 \uc800\uc7a5\uc18c\ub97c \uc9c0\uc815\ud574\uc57c \ud569\ub2c8\ub2e4. | |||
gb.teamCreated = \uc0c8\ub85c\uc6b4 \ud300 ''{0}'' \uc0dd\uc131 \uc644\ub8cc. | |||
gb.pleaseSetUsername = \uc720\uc800\ub124\uc784\uc744 \uc785\ub825\ud558\uc138\uc694! | |||
gb.usernameUnavailable = ''{0}'' \uc720\uc800\ub124\uc784\uc740 \uc0ac\uc6a9\ud560 \uc218 \uc5c6\uc5b4\uc694. | |||
gb.combinedMd5Rename = Gitblit \uc740 combined-md5 \ud574\uc2f1 \ud328\uc2a4\uc6cc\ub4dc\ub85c \uc124\uc815\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \uacc4\uc815 \uc774\ub984 \ubcc0\uacbd \uc2dc \uc0c8 \ud328\uc2a4\uc6cc\ub4dc\ub97c \uc785\ub825\ud574\uc57c \ud569\ub2c8\ub2e4. | |||
gb.userCreated = \uc0c8\ub85c\uc6b4 \uc720\uc800 ''{0}'' \uc0dd\uc131 \uc644\ub8cc. | |||
gb.couldNotFindFederationRegistration = \ud398\ub354\ub808\uc774\uc158 \ub4f1\ub85d\uc744 \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4! | |||
gb.failedToFindGravatarProfile = {0} \uc758 Gravatar \ud504\ub85c\ud30c\uc77c \ucc3e\uae30 \uc2e4\ud328 | |||
gb.branchStats = {2} \uc548\uc5d0 {0} \ucee4\ubc0b {1} \ud0dc\uadf8 | |||
gb.repositoryNotSpecified = \uc800\uc7a5\uc18c\uac00 \uc9c0\uc815\ub418\uc9c0 \uc54a\uc74c! | |||
gb.repositoryNotSpecifiedFor = {0} \ub97c \uc704\ud55c \uc800\uc7a5\uc18c\uac00 \uc9c0\uc815\ub418\uc9c0 \uc54a\uc74c! | |||
gb.canNotLoadRepository = \uc800\uc7a5\uc18c\ub97c \ubd88\ub7ec\uc62c \uc218 \uc5c6\uc74c | |||
gb.commitIsNull = \ub110 \ucee4\ubc0b | |||
gb.unauthorizedAccessForRepository = \uc800\uc7a5\uc18c\uc5d0 \uc811\uadfc \ud5c8\uc6a9\ub418\uc9c0 \uc54a\uc74c | |||
gb.failedToFindCommit = \ucee4\ubc0b\uc744 \ucc3e\uc744 \uc218 \uc5c6\uc74c \"{0}\" in {1} for {2} \ud398\uc774\uc9c0! | |||
gb.couldNotFindFederationProposal = \ud398\ub354\ub808\uc774\uc158 \uc81c\uc548\uc744 \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4! | |||
gb.invalidUsernameOrPassword = \uc798\ubabb\ub41c \uc720\uc800\ub124\uc784 \ub610\ub294 \ud328\uc2a4\uc6cc\ub4dc! | |||
gb.OneProposalToReview = \uac80\ud1a0\ub97c \uae30\ub2e4\ub9ac\uace0 \uc788\ub294 1\uac1c\uc758 \ud398\ub354\ub808\uc774\uc158 \uc81c\uc548\uc774 \uc788\uc2b5\ub2c8\ub2e4. | |||
gb.nFederationProposalsToReview = \uac80\ud1a0\ub97c \uae30\ub2e4\ub9ac\uace0 \uc788\ub294 {0} \uac1c\uc758 \ud398\ub354\ub808\uc774\uc158 \uc81c\uc548\uc774 \uc788\uc2b5\ub2c8\ub2e4. | |||
gb.couldNotFindTag = \ud0dc\uadf8 {0} \ub97c(\uc744) \ucc3e\uc744 \uc218 \uc5c6\uc74c | |||
gb.couldNotCreateFederationProposal = \ud398\ub354\ub808\uc774\uc158 \uc81c\uc548 \uc0dd\uc131 \uc2e4\ud328! | |||
gb.pleaseSetGitblitUrl = Gitblit url \uc744 \uc785\ub825\ud558\uc138\uc694! | |||
gb.pleaseSetDestinationUrl = \ub2f9\uc2e0\uc758 \uc81c\uc548\uc5d0 \ub300\ud55c \ub300\uc0c1 url \uc744 \uc785\ub825\ud558\uc138\uc694! | |||
gb.proposalReceived = {0} \uc758 \uc81c\uc548 \uc131\uacf5\uc801 \uc218\uc2e0 | |||
gb.noGitblitFound = \uc8c4\uc1a1\ud569\ub2c8\ub2e4, Gitblit \uc778\uc2a4\ud134\uc2a4 {1} \uc5d0\uc11c {0} \ub97c \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. | |||
gb.noProposals = \uc8c4\uc1a1\ud569\ub2c8\ub2e4, \uc774\ubc88\uc5d0\ub294 {0} \uc758 \uc81c\uc548\uc744 \uc218\uc6a9\ud558\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. | |||
gb.noFederation = \uc8c4\uc1a1\ud569\ub2c8\ub2e4, {0} \uc5d0\ub294 \ud398\ub354\ub808\uc774\uc158 \uc124\uc815\ub41c Gitblit \uc778\uc2a4\ud134\uc2a4\uac00 \uc5c6\uc2b5\ub2c8\ub2e4. | |||
gb.proposalFailed = \uc8c4\uc1a1\ud569\ub2c8\ub2e4, {0} \uc5d0\ub294 \uc81c\uc548 \ub370\uc774\ud130\ub97c \ubc1b\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. | |||
gb.proposalError = \uc8c4\uc1a1\ud569\ub2c8\ub2e4, {0} \uc5d0 \ub300\ud55c \uc624\ub958 \ubc1c\uc0dd \ubcf4\uace0 | |||
gb.failedToSendProposal = \uc81c\uc548 \ubcf4\ub0b4\uae30 \uc2e4\ud328! | |||
gb.userServiceDoesNotPermitAddUser = {0} \uc0c8\ub85c\uc6b4 \uc720\uc800\ub97c \ucd94\uac00\ud560 \uc218 \uc5c6\uc74c! | |||
gb.userServiceDoesNotPermitPasswordChanges = {0} \ud328\uc2a4\uc6cc\ub4dc\ub97c \ubcc0\uacbd\ud560 \uc218 \uc5c6\uc74c! | |||
gb.displayName = \ud45c\uc2dc\ub418\ub294 \uc774\ub984 | |||
gb.emailAddress = \uc774\uba54\uc77c \uc8fc\uc18c | |||
gb.errorAdminLoginRequired = \uad00\ub9ac\ub97c \uc704\ud574\uc11c\ub294 \ub85c\uadf8\uc778\uc774 \ud544\uc694 | |||
gb.errorOnlyAdminMayCreateRepository = \uad00\ub9ac\uc790\ub9cc \uc800\uc7a5\uc18c\ub97c \ub9cc\ub4e4\uc218 \uc788\uc74c | |||
gb.errorOnlyAdminOrOwnerMayEditRepository = \uad00\ub9ac\uc790\uc640 \uc18c\uc720\uc790\ub9cc \uc800\uc7a5\uc18c\ub97c \uc218\uc815\ud560 \uc218 \uc788\uc74c | |||
gb.errorAdministrationDisabled = \uad00\ub9ac\uae30\ub2a5 \ube44\ud65c\uc131\ud654\ub428 | |||
gb.lastNDays = {0} \uc77c\uc804 | |||
gb.completeGravatarProfile = Gravatar.com \uc5d0 \ud504\ub85c\ud30c\uc77c \uc0dd\uc131\ub428 | |||
gb.none = none | |||
gb.line = \uB77C\uC778 | |||
gb.content = \uB0B4\uC6A9 | |||
@@ -782,4 +783,4 @@ gb.deletePatchset = {0} \uD328\uCE58\uC14B \uC0AD\uC81C | |||
gb.deletePatchsetSuccess = {0} \uD328\uCE58\uC14B\uC774 \uC0AD\uC81C\uB418\uC5C8\uC5B4\uC694. | |||
gb.deletePatchsetFailure = {0} \uD328\uCE58\uC14B \uC0AD\uC81C \uC624\uB958. | |||
gb.referencedByCommit = \uCEE4\uBC0B\uC5D0 \uCC38\uC870\uB428. | |||
gb.referencedByTicket = \uD2F0\uCF13\uC5D0 \uCC38\uC870\uB428. | |||
gb.referencedByTicket = \uD2F0\uCF13\uC5D0 \uCC38\uC870\uB428. |
@@ -218,7 +218,8 @@ gb.pages = paginas | |||
gb.workingCopy = werkkopie | |||
gb.workingCopyWarning = deze repositorie heeft een werkkopie en kan geen pushes ontvangen | |||
gb.query = query | |||
gb.queryHelp = Standaard query syntax wordt ondersteund.<p/><p/>Zie aub <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> voor informatie. | |||
gb.queryHelp = Standaard query syntax wordt ondersteund.<p/><p/>Zie aub ${querySyntax} voor informatie. | |||
gb.querySyntax = Lucene Query Parser Syntax | |||
gb.queryResults = resultaten {0} - {1} ({2} hits) | |||
gb.noHits = geen hits | |||
gb.authored = geschreven |
@@ -218,7 +218,8 @@ gb.pages = sider | |||
gb.workingCopy = arbeidskopi | |||
gb.workingCopyWarning = dette repositoriet har en arbeidskopi, og kan ikke pushes til. | |||
gb.query = sp\u00F8rring | |||
gb.queryHelp = Standard lucene sp\u00F8rringssyntaks st\u00F8ttes.<p/><p/>Se <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> for mer info. | |||
gb.queryHelp = Standard lucene sp\u00F8rringssyntaks st\u00F8ttes.<p/><p/>Se ${querySyntax} for mer info. | |||
gb.querySyntax = Lucene Query Parser Syntax | |||
gb.queryResults = resultater {0} - {1} ({2} treff) | |||
gb.noHits = ingen treff | |||
gb.authored = forfattet |
@@ -217,7 +217,8 @@ gb.pages = Strony | |||
gb.workingCopy = Kopia robocza | |||
gb.workingCopyWarning = To repozytorium ma kopi\u0119 robocz\u0105 i nie mo\u017Ce otrzymywa\u0107 zmian | |||
gb.query = Szukaj | |||
gb.queryHelp = Standardowa sk\u0142adnia wyszukiwa\u0144 jest wspierana.<p/><p/>Na stronie <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> dost\u0119pne s\u0105 dalsze szczeg\u00F3\u0142y. | |||
gb.queryHelp = Standardowa sk\u0142adnia wyszukiwa\u0144 jest wspierana.<p/><p/>Na stronie ${querySyntax} dost\u0119pne s\u0105 dalsze szczeg\u00F3\u0142y. | |||
gb.querySyntax = Lucene Query Parser Syntax | |||
gb.queryResults = Wyniki {0} - {1} ({2} wynik\u00F3w) | |||
gb.noHits = Brak wynik\u00F3w | |||
gb.authored = utworzy\u0142 |
@@ -217,7 +217,8 @@ gb.pages = p | |||
gb.workingCopy = working copy | |||
gb.workingCopyWarning = este repositório tem uma working copy e não pode receber pushes | |||
gb.query = query | |||
gb.queryHelp = Standard query syntax é suportada.<p/><p/>Por favor veja <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> para mais detalhes. | |||
gb.queryHelp = Standard query syntax é suportada.<p/><p/>Por favor veja ${querySyntax} para mais detalhes. | |||
gb.querySyntax = Lucene Query Parser Syntax | |||
gb.queryResults = resultados {0} - {1} ({2} hits) | |||
gb.noHits = sem hits | |||
gb.authored = foi autor de |
@@ -218,7 +218,8 @@ gb.pages = \u9875\u9762 | |||
gb.workingCopy = \u5de5\u4f5c\u526f\u672c | |||
gb.workingCopyWarning = \u6b64\u7248\u672c\u5e93\u5b58\u5728\u4e00\u4efd\u5de5\u4f5c\u526f\u672c\uff0c\u65e0\u6cd5\u8fdb\u884c\u63a8\u9001 | |||
gb.query = \u67e5\u8be2 | |||
gb.queryHelp = \u652f\u6301\u6807\u51c6\u67e5\u8be2\u683c\u5f0f.<p/><p/>\u8bf7\u67e5\u770b <a target="_new" href="http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene \u67e5\u8be2\u5904\u7406\u5668\u683c\u5f0f</a> \u4ee5\u83b7\u53d6\u8be6\u7ec6\u5185\u5bb9\u3002 | |||
gb.queryHelp = \u652f\u6301\u6807\u51c6\u67e5\u8be2\u683c\u5f0f.<p/><p/>\u8bf7\u67e5\u770b ${querySyntax} \u4ee5\u83b7\u53d6\u8be6\u7ec6\u5185\u5bb9\u3002 | |||
gb.querySyntax = Lucene \u67e5\u8be2\u5904\u7406\u5668\u683c\u5f0f | |||
gb.queryResults = \u7ed3\u679c {0} - {1} ({2} \u6b21\u547d\u4e2d) | |||
gb.noHits = \u672a\u547d\u4e2d | |||
gb.authored = authored |
@@ -219,7 +219,8 @@ gb.pages = \u6587\u4ef6 | |||
gb.workingCopy = \u66ab\u5b58\u8907\u672c | |||
gb.workingCopyWarning = \u8a72\u7248\u672c\u5eab\u4ecd\u6709\u66ab\u5b58\u8907\u672c,\u56e0\u6b64\u7121\u6cd5\u63a5\u53d7\u63a8\u9001(push) | |||
gb.query = \u67e5\u8a62 | |||
gb.queryHelp = \u652f\u63f4\u6a19\u6e96\u67e5\u8a62\u8a9e\u6cd5.<p/><p/>\u8a73\u60c5\u8acb\u53c3\u8003 <a target\ = "_new" href\ = "http\://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/queryparsersyntax.html">Lucene Query Parser Syntax</a> | |||
gb.queryHelp = \u652f\u63f4\u6a19\u6e96\u67e5\u8a62\u8a9e\u6cd5.<p/><p/>\u8a73\u60c5\u8acb\u53c3\u8003 ${querySyntax} | |||
gb.querySyntax = Lucene Query Parser Syntax | |||
gb.queryResults = \u7d50\u679c {0} - {1} ({2} \u67e5\u8a62) | |||
gb.noHits = \u7121\u9ede\u64ca | |||
gb.authored = \u6388\u6b0a |
@@ -52,7 +52,9 @@ | |||
</div> | |||
</div> | |||
<div style="margin-left:10px;" class="span2"> | |||
<wicket:message key="gb.queryHelp"></wicket:message> | |||
<wicket:message key="gb.queryHelp"> | |||
<a target="_new" wicket:id="querySyntax"><wicket:message key="gb.querySyntax"/></a> | |||
</wicket:message> | |||
</div> | |||
</div> | |||
</div> |
@@ -27,6 +27,7 @@ import org.apache.wicket.markup.html.basic.Label; | |||
import org.apache.wicket.markup.html.form.CheckBox; | |||
import org.apache.wicket.markup.html.form.ListMultipleChoice; | |||
import org.apache.wicket.markup.html.form.TextField; | |||
import org.apache.wicket.markup.html.link.ExternalLink; | |||
import org.apache.wicket.markup.html.panel.Fragment; | |||
import org.apache.wicket.markup.repeater.Item; | |||
import org.apache.wicket.markup.repeater.data.DataView; | |||
@@ -50,6 +51,8 @@ import com.gitblit.wicket.panels.PagerPanel; | |||
public class LuceneSearchPage extends RootPage { | |||
private final static String LUCENE_QUERY_SYNTAX_LINK = "https://lucene.apache.org/core/5_5_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package_description"; | |||
public LuceneSearchPage() { | |||
super(); | |||
setup(null); | |||
@@ -167,6 +170,7 @@ public class LuceneSearchPage extends RootPage { | |||
form.add(selections.setEnabled(luceneEnabled)); | |||
form.add(new TextField<String>("query", queryModel).setEnabled(luceneEnabled)); | |||
form.add(new CheckBox("allrepos", allreposModel)); | |||
form.add(new ExternalLink("querySyntax", LUCENE_QUERY_SYNTAX_LINK)); | |||
add(form.setEnabled(luceneEnabled)); | |||
// execute search |
@@ -0,0 +1,267 @@ | |||
/* | |||
* Copyright 2017 gitblit.com. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package com.gitblit.service; | |||
import static org.junit.Assert.*; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.nio.file.Path; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.TemporaryFolder; | |||
import com.gitblit.utils.LuceneIndexStore; | |||
/** | |||
* @author Florian Zschocke | |||
* | |||
*/ | |||
public class LuceneRepoIndexStoreTest | |||
{ | |||
private static final int LUCENE_VERSION = LuceneIndexStore.LUCENE_CODEC_VERSION; | |||
private static final String LUCENE_DIR = "lucene"; | |||
@Rule | |||
public TemporaryFolder baseFolder = new TemporaryFolder(); | |||
private String getIndexDir(int version) | |||
{ | |||
return version + "_" + LUCENE_VERSION; | |||
} | |||
private String getLuceneIndexDir(int version) | |||
{ | |||
return LUCENE_DIR + "/" + version + "_" + LUCENE_VERSION; | |||
} | |||
@Test | |||
public void testGetConfigFile() throws IOException | |||
{ | |||
int version = 1; | |||
File repositoryFolder = baseFolder.getRoot(); | |||
LuceneRepoIndexStore li = new LuceneRepoIndexStore(repositoryFolder, version); | |||
File confFile= li.getConfigFile(); | |||
File luceneDir = new File(repositoryFolder, getLuceneIndexDir(version) + "/gb_lucene.conf"); | |||
assertEquals(luceneDir, confFile); | |||
} | |||
@Test | |||
public void testCreate() | |||
{ | |||
int version = 0; | |||
File repositoryFolder = baseFolder.getRoot(); | |||
File luceneDir = new File(repositoryFolder, getLuceneIndexDir(version)); | |||
assertFalse("Precondition failure: directory exists already", new File(repositoryFolder, LUCENE_DIR).exists()); | |||
assertFalse("Precondition failure: directory exists already", luceneDir.exists()); | |||
LuceneIndexStore li = new LuceneRepoIndexStore(repositoryFolder, version); | |||
li.create(); | |||
assertTrue(luceneDir.exists()); | |||
assertTrue(luceneDir.isDirectory()); | |||
} | |||
@Test | |||
public void testCreateIndexDir() | |||
{ | |||
int version = 7777; | |||
File repositoryFolder = baseFolder.getRoot(); | |||
try { | |||
baseFolder.newFolder(LUCENE_DIR); | |||
} catch (IOException e) { | |||
fail("Failed in setup of folder: " + e); | |||
} | |||
File luceneDir = new File(repositoryFolder, getLuceneIndexDir(version)); | |||
assertTrue("Precondition failure: directory does not exist", new File(repositoryFolder, LUCENE_DIR).exists()); | |||
assertFalse("Precondition failure: directory exists already", luceneDir.exists()); | |||
LuceneIndexStore li = new LuceneRepoIndexStore(repositoryFolder, version); | |||
li.create(); | |||
assertTrue(luceneDir.exists()); | |||
assertTrue(luceneDir.isDirectory()); | |||
// Make sure nothing else was created. | |||
assertEquals(0, luceneDir.list().length); | |||
assertEquals(1, luceneDir.getParentFile().list().length); | |||
} | |||
@Test | |||
public void testCreateIfNecessary() | |||
{ | |||
int version = 7777888; | |||
File repositoryFolder = baseFolder.getRoot(); | |||
File luceneDir = null; | |||
try { | |||
luceneDir = baseFolder.newFolder(LUCENE_DIR, getIndexDir(version)); | |||
} catch (IOException e) { | |||
fail("Failed in setup of folder: " + e); | |||
} | |||
assertTrue("Precondition failure: directory does not exist", new File(repositoryFolder, LUCENE_DIR).exists()); | |||
assertTrue("Precondition failure: directory does not exist", luceneDir.exists()); | |||
LuceneIndexStore li = new LuceneRepoIndexStore(repositoryFolder, version); | |||
li.create(); | |||
assertTrue(luceneDir.exists()); | |||
assertTrue(luceneDir.isDirectory()); | |||
// Make sure nothing else was created. | |||
assertEquals(0, luceneDir.list().length); | |||
assertEquals(1, luceneDir.getParentFile().list().length); | |||
} | |||
@Test | |||
public void testDelete() | |||
{ | |||
int version = 111222333; | |||
File repositoryFolder = baseFolder.getRoot(); | |||
File luceneDir = null; | |||
try { | |||
luceneDir = baseFolder.newFolder(LUCENE_DIR, getIndexDir(version)); | |||
} catch (IOException e) { | |||
fail("Failed in setup of folder: " + e); | |||
} | |||
assertTrue("Precondition failure: directory does not exist", luceneDir.exists()); | |||
LuceneIndexStore li = new LuceneRepoIndexStore(repositoryFolder, version); | |||
assertTrue(li.delete()); | |||
assertFalse(luceneDir.exists()); | |||
assertTrue(new File(repositoryFolder, LUCENE_DIR).exists()); | |||
} | |||
@Test | |||
public void testDeleteNotExist() | |||
{ | |||
int version = 0; | |||
File repositoryFolder = baseFolder.getRoot(); | |||
try { | |||
baseFolder.newFolder(LUCENE_DIR); | |||
} catch (IOException e) { | |||
fail("Failed in setup of folder: " + e); | |||
} | |||
File luceneDir = new File(repositoryFolder, getLuceneIndexDir(version)); | |||
assertTrue("Precondition failure: directory does not exist", new File(repositoryFolder, LUCENE_DIR).exists()); | |||
assertFalse("Precondition failure: directory does exist", luceneDir.exists()); | |||
LuceneIndexStore li = new LuceneRepoIndexStore(repositoryFolder, version); | |||
assertTrue(li.delete()); | |||
assertFalse(luceneDir.exists()); | |||
assertTrue(new File(repositoryFolder, LUCENE_DIR).exists()); | |||
} | |||
@Test | |||
public void testDeleteWithFiles() | |||
{ | |||
int version = 5; | |||
File repositoryFolder = baseFolder.getRoot(); | |||
File luceneFolder = new File(baseFolder.getRoot(), LUCENE_DIR); | |||
File luceneDir = null; | |||
File otherDir = new File(luceneFolder, version + "_10"); | |||
File dbFile = null; | |||
try { | |||
luceneDir = baseFolder.newFolder(LUCENE_DIR, getIndexDir(version)); | |||
File file = new File(luceneDir, "_file1"); | |||
file.createNewFile(); | |||
file = new File(luceneDir, "_file2.db"); | |||
file.createNewFile(); | |||
file = new File(luceneDir, "conf.conf"); | |||
file.createNewFile(); | |||
otherDir.mkdirs(); | |||
dbFile = new File(otherDir, "_file2.db"); | |||
dbFile.createNewFile(); | |||
file = new File(otherDir, "conf.conf"); | |||
file.createNewFile(); | |||
} | |||
catch (IOException e) { | |||
fail("Failed in setup of folder: " + e); | |||
} | |||
assertTrue("Precondition failure: index directory does not exist", luceneDir.exists()); | |||
assertTrue("Precondition failure: other index directory does not exist", otherDir.exists()); | |||
LuceneIndexStore li = new LuceneRepoIndexStore(repositoryFolder, version); | |||
li.delete(); | |||
assertFalse(luceneDir.exists()); | |||
assertTrue(luceneFolder.exists()); | |||
assertTrue(otherDir.exists()); | |||
assertTrue(dbFile.exists()); | |||
} | |||
@Test | |||
public void testGetPath() throws IOException | |||
{ | |||
int version = 7; | |||
File repositoryFolder = baseFolder.getRoot(); | |||
LuceneIndexStore li = new LuceneRepoIndexStore(repositoryFolder, version); | |||
Path dir = li.getPath(); | |||
File luceneDir = new File(repositoryFolder, getLuceneIndexDir(version)); | |||
assertEquals(luceneDir.toPath(), dir); | |||
} | |||
@Test | |||
public void testHasIndex() throws IOException | |||
{ | |||
int version = 0; | |||
File luceneFolder = new File(baseFolder.getRoot(), "lucene"); | |||
LuceneIndexStore li = new LuceneRepoIndexStore(luceneFolder, version); | |||
assertFalse(li.hasIndex()); | |||
baseFolder.newFolder("lucene"); | |||
li = new LuceneIndexStore(luceneFolder, version); | |||
assertFalse(li.hasIndex()); | |||
File luceneDir = baseFolder.newFolder("lucene", getIndexDir(version)); | |||
li = new LuceneIndexStore(luceneFolder, version); | |||
assertFalse(li.hasIndex()); | |||
new File(luceneDir, "write.lock").createNewFile(); | |||
li = new LuceneIndexStore(luceneFolder, version); | |||
assertFalse(li.hasIndex()); | |||
new File(luceneDir, "segments_1").createNewFile(); | |||
li = new LuceneIndexStore(luceneFolder, version); | |||
System.out.println("Check " + luceneDir); | |||
assertTrue(li.hasIndex()); | |||
} | |||
} |
@@ -59,7 +59,7 @@ public class BranchTicketServiceTest extends TicketServiceTest { | |||
IUserManager userManager = new UserManager(runtimeManager, pluginManager).start(); | |||
IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, pluginManager, userManager).start(); | |||
BranchTicketService service = new BranchTicketService( | |||
BranchTicketService service = (BranchTicketService) new BranchTicketService( | |||
runtimeManager, | |||
pluginManager, | |||
notificationManager, |
@@ -58,7 +58,7 @@ public class FileTicketServiceTest extends TicketServiceTest { | |||
IUserManager userManager = new UserManager(runtimeManager, pluginManager).start(); | |||
IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, pluginManager, userManager).start(); | |||
FileTicketService service = new FileTicketService( | |||
FileTicketService service = (FileTicketService) new FileTicketService( | |||
runtimeManager, | |||
pluginManager, | |||
notificationManager, |
@@ -66,7 +66,7 @@ public class RedisTicketServiceTest extends TicketServiceTest { | |||
IUserManager userManager = new UserManager(runtimeManager, pluginManager).start(); | |||
IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, pluginManager, userManager).start(); | |||
RedisTicketService service = new RedisTicketService( | |||
RedisTicketService service = (RedisTicketService) new RedisTicketService( | |||
runtimeManager, | |||
pluginManager, | |||
notificationManager, |
@@ -83,7 +83,7 @@ public class UITicketTest extends GitblitUnitTest { | |||
IUserManager userManager = new UserManager(runtimeManager, pluginManager).start(); | |||
IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, pluginManager, userManager).start(); | |||
BranchTicketService service = new BranchTicketService( | |||
BranchTicketService service = (BranchTicketService) new BranchTicketService( | |||
runtimeManager, | |||
pluginManager, | |||
notificationManager, |
@@ -0,0 +1,245 @@ | |||
/* | |||
* Copyright 2017 gitblit.com. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package com.gitblit.utils; | |||
import static org.junit.Assert.*; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.nio.file.Path; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.TemporaryFolder; | |||
/** | |||
* @author Florian Zschocke | |||
* | |||
*/ | |||
public class LuceneIndexStoreTest | |||
{ | |||
private final int LUCENE_VERSION = LuceneIndexStore.LUCENE_CODEC_VERSION; | |||
@Rule | |||
public TemporaryFolder baseFolder = new TemporaryFolder(); | |||
private String getIndexDir(int version) | |||
{ | |||
return version + "_" + LUCENE_VERSION; | |||
} | |||
@Test | |||
public void testCreate() | |||
{ | |||
int version = 0; | |||
File luceneFolder = new File(baseFolder.getRoot(), "tickets/lucene"); | |||
assertFalse("Precondition failure: directory exists already", luceneFolder.exists()); | |||
LuceneIndexStore li = new LuceneIndexStore(luceneFolder, version); | |||
li.create(); | |||
File luceneDir = new File(luceneFolder, getIndexDir(version)); | |||
assertTrue(luceneDir.exists()); | |||
} | |||
@Test | |||
public void testCreateIndexDir() | |||
{ | |||
int version = 111222; | |||
File luceneFolder = null; | |||
try { | |||
luceneFolder = baseFolder.newFolder("tickets", "lucene"); | |||
} | |||
catch (IOException e) { | |||
fail("Failed in setup of folder: " + e); | |||
} | |||
assertTrue("Precondition failure: directory does not exist", luceneFolder.exists()); | |||
LuceneIndexStore li = new LuceneIndexStore(luceneFolder, version); | |||
li.create(); | |||
File luceneDir = new File(luceneFolder, getIndexDir(version)); | |||
assertTrue(luceneDir.exists()); | |||
assertTrue(luceneDir.isDirectory()); | |||
// Make sure nothing else was created. | |||
assertEquals(0, luceneDir.list().length); | |||
assertEquals(1, luceneDir.getParentFile().list().length); | |||
assertEquals(1, luceneDir.getParentFile().getParentFile().list().length); | |||
} | |||
@Test | |||
public void testCreateIfNecessary() | |||
{ | |||
int version = 1; | |||
File luceneFolder = new File(baseFolder.getRoot(), "tickets/lucene"); | |||
File luceneDir = null; | |||
try { | |||
luceneDir = baseFolder.newFolder("tickets", "lucene", getIndexDir(version)); | |||
} | |||
catch (IOException e) { | |||
fail("Failed in setup of folder: " + e); | |||
} | |||
assertTrue("Precondition failure: directory does not exist", luceneDir.exists()); | |||
LuceneIndexStore li = new LuceneIndexStore(luceneFolder, version); | |||
li.create(); | |||
assertTrue(luceneDir.exists()); | |||
assertTrue(luceneDir.isDirectory()); | |||
// Make sure nothing else was created. | |||
assertEquals(0, luceneDir.list().length); | |||
assertEquals(1, luceneDir.getParentFile().list().length); | |||
assertEquals(1, luceneDir.getParentFile().getParentFile().list().length); | |||
} | |||
@Test | |||
public void testDelete() | |||
{ | |||
int version = 111222333; | |||
File luceneFolder = new File(baseFolder.getRoot(), "repo1/lucene"); | |||
File luceneDir = null; | |||
try { | |||
luceneDir = baseFolder.newFolder("repo1", "lucene", getIndexDir(version)); | |||
} | |||
catch (IOException e) { | |||
fail("Failed in setup of folder: " + e); | |||
} | |||
assertTrue("Precondition failure: index directory does not exist", luceneDir.exists()); | |||
LuceneIndexStore li = new LuceneIndexStore(luceneFolder, version); | |||
assertTrue(li.delete()); | |||
assertFalse(luceneDir.exists()); | |||
assertTrue(luceneFolder.exists()); | |||
} | |||
@Test | |||
public void testDeleteNotExist() | |||
{ | |||
int version = 0; | |||
File luceneFolder = null; | |||
try { | |||
luceneFolder = baseFolder.newFolder("repo1", "lucene"); | |||
} | |||
catch (IOException e) { | |||
fail("Failed in setup of folder: " + e); | |||
} | |||
File luceneDir = new File(luceneFolder, getIndexDir(version)); | |||
assertFalse("Precondition failure: index directory exists already", luceneDir.exists()); | |||
LuceneIndexStore li = new LuceneIndexStore(luceneFolder, version); | |||
assertTrue(li.delete()); | |||
assertFalse(luceneDir.exists()); | |||
assertTrue(luceneFolder.exists()); | |||
} | |||
@Test | |||
public void testDeleteWithFiles() | |||
{ | |||
int version = 111222333; | |||
File luceneFolder = new File(baseFolder.getRoot(), "tickets/lucene"); | |||
File luceneDir = null; | |||
File otherDir = new File(baseFolder.getRoot(), "tickets/lucene/" + version + "_10"); | |||
File dbFile = null; | |||
try { | |||
luceneDir = baseFolder.newFolder("tickets", "lucene", getIndexDir(version)); | |||
File file = new File(luceneDir, "_file1"); | |||
file.createNewFile(); | |||
file = new File(luceneDir, "_file2.db"); | |||
file.createNewFile(); | |||
file = new File(luceneDir, "conf.conf"); | |||
file.createNewFile(); | |||
otherDir.mkdirs(); | |||
dbFile = new File(otherDir, "_file2.db"); | |||
dbFile.createNewFile(); | |||
file = new File(otherDir, "conf.conf"); | |||
file.createNewFile(); | |||
} | |||
catch (IOException e) { | |||
fail("Failed in setup of folder: " + e); | |||
} | |||
assertTrue("Precondition failure: index directory does not exist", luceneDir.exists()); | |||
assertTrue("Precondition failure: other index directory does not exist", otherDir.exists()); | |||
LuceneIndexStore li = new LuceneIndexStore(luceneFolder, version); | |||
li.delete(); | |||
assertFalse(luceneDir.exists()); | |||
assertTrue(luceneFolder.exists()); | |||
assertTrue(otherDir.exists()); | |||
assertTrue(dbFile.exists()); | |||
} | |||
@Test | |||
public void testGetPath() throws IOException | |||
{ | |||
int version = 2; | |||
File luceneFolder = baseFolder.newFolder("tickets", "lucene"); | |||
LuceneIndexStore li = new LuceneIndexStore(luceneFolder, version); | |||
Path dir = li.getPath(); | |||
File luceneDir = new File(luceneFolder, getIndexDir(version)); | |||
assertEquals(luceneDir.toPath(), dir); | |||
} | |||
@Test | |||
public void testHasIndex() throws IOException | |||
{ | |||
int version = 0; | |||
File luceneFolder = new File(baseFolder.getRoot(), "ticktock/lucene"); | |||
LuceneIndexStore li = new LuceneIndexStore(luceneFolder, version); | |||
assertFalse(li.hasIndex()); | |||
baseFolder.newFolder("ticktock"); | |||
li = new LuceneIndexStore(luceneFolder, version); | |||
assertFalse(li.hasIndex()); | |||
baseFolder.newFolder("ticktock", "lucene"); | |||
li = new LuceneIndexStore(luceneFolder, version); | |||
assertFalse(li.hasIndex()); | |||
File luceneDir = baseFolder.newFolder("ticktock", "lucene", getIndexDir(version)); | |||
li = new LuceneIndexStore(luceneFolder, version); | |||
assertFalse(li.hasIndex()); | |||
new File(luceneDir, "write.lock").createNewFile(); | |||
li = new LuceneIndexStore(luceneFolder, version); | |||
assertFalse(li.hasIndex()); | |||
new File(luceneDir, "segments_1").createNewFile(); | |||
li = new LuceneIndexStore(luceneFolder, version); | |||
assertTrue(li.hasIndex()); | |||
} | |||
} |