From 2e03db322ea93cac67275bdd584a67b559ed185a Mon Sep 17 00:00:00 2001 From: Luca Milanesio Date: Thu, 22 Dec 2016 00:42:56 +0000 Subject: Bump to Lucene 5.5.2 --- .../java/com/gitblit/service/LuceneService.java | 22 ++++++++-------- .../java/com/gitblit/tickets/TicketIndexer.java | 30 +++++++++++----------- 2 files changed, 26 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/main/java/com/gitblit/service/LuceneService.java b/src/main/java/com/gitblit/service/LuceneService.java index 097a39b2..59b1ff24 100644 --- a/src/main/java/com/gitblit/service/LuceneService.java +++ b/src/main/java/com/gitblit/service/LuceneService.java @@ -267,7 +267,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); } @@ -722,8 +722,8 @@ public class LuceneService implements Runnable { 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); + StandardAnalyzer analyzer = new StandardAnalyzer(); + QueryParser qp = new QueryParser(FIELD_SUMMARY, analyzer); query.add(qp.parse(q), Occur.MUST); IndexWriter writer = getIndexWriter(repositoryName); @@ -968,14 +968,14 @@ public class LuceneService implements Runnable { 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); + Directory directory = FSDirectory.open(indexFolder.toPath()); if (indexWriter == null) { if (!indexFolder.exists()) { indexFolder.mkdirs(); } - StandardAnalyzer analyzer = new StandardAnalyzer(LUCENE_VERSION); - IndexWriterConfig config = new IndexWriterConfig(LUCENE_VERSION, analyzer); + 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,16 +1028,16 @@ public class LuceneService implements Runnable { return null; } Set results = new LinkedHashSet(); - StandardAnalyzer analyzer = new StandardAnalyzer(LUCENE_VERSION); + StandardAnalyzer analyzer = new StandardAnalyzer(); try { // default search checks summary and content BooleanQuery query = new BooleanQuery(); 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); - qp = new QueryParser(LUCENE_VERSION, FIELD_CONTENT, analyzer); + qp = new QueryParser(FIELD_CONTENT, analyzer); qp.setAllowLeadingWildcard(true); query.add(qp.parse(text), Occur.SHOULD); @@ -1060,7 +1060,7 @@ public class LuceneService implements Runnable { 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 +1225,7 @@ public class LuceneService implements Runnable { */ private class MultiSourceReader extends MultiReader { - MultiSourceReader(IndexReader [] readers) { + MultiSourceReader(IndexReader [] readers) throws IOException { super(readers, false); } diff --git a/src/main/java/com/gitblit/tickets/TicketIndexer.java b/src/main/java/com/gitblit/tickets/TicketIndexer.java index e2d53af7..02af25ef 100644 --- a/src/main/java/com/gitblit/tickets/TicketIndexer.java +++ b/src/main/java/com/gitblit/tickets/TicketIndexer.java @@ -167,7 +167,7 @@ public class TicketIndexer { private final Logger log = LoggerFactory.getLogger(getClass()); - private final Version luceneVersion = Version.LUCENE_46; + private final Version luceneVersion = Version.LUCENE_5_5_2; private final File luceneDir; @@ -201,8 +201,8 @@ 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); + StandardAnalyzer analyzer = new StandardAnalyzer(); + QueryParser qp = new QueryParser(Lucene.rid.name(), analyzer); BooleanQuery query = new BooleanQuery(); query.add(qp.parse(repository.getRID()), Occur.MUST); @@ -287,8 +287,8 @@ 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); + StandardAnalyzer analyzer = new StandardAnalyzer(); + QueryParser qp = new QueryParser(Lucene.did.name(), analyzer); BooleanQuery query = new BooleanQuery(); query.add(qp.parse(StringUtils.getSHA1(repository + ticketId)), Occur.MUST); @@ -331,21 +331,21 @@ public class TicketIndexer { return Collections.emptyList(); } Set results = new LinkedHashSet(); - StandardAnalyzer analyzer = new StandardAnalyzer(luceneVersion); + StandardAnalyzer analyzer = new StandardAnalyzer(); try { // search the title, description and content BooleanQuery query = new BooleanQuery(); 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); - 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); - 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); @@ -354,7 +354,7 @@ public class TicketIndexer { 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 +392,9 @@ public class TicketIndexer { } Set results = new LinkedHashSet(); - 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(); @@ -443,14 +443,14 @@ public class TicketIndexer { private IndexWriter getWriter() throws IOException { if (writer == null) { - Directory directory = FSDirectory.open(luceneDir); + Directory directory = FSDirectory.open(luceneDir.toPath()); if (!luceneDir.exists()) { luceneDir.mkdirs(); } - StandardAnalyzer analyzer = new StandardAnalyzer(luceneVersion); - IndexWriterConfig config = new IndexWriterConfig(luceneVersion, analyzer); + StandardAnalyzer analyzer = new StandardAnalyzer(); + IndexWriterConfig config = new IndexWriterConfig(analyzer); config.setOpenMode(OpenMode.CREATE_OR_APPEND); writer = new IndexWriter(directory, config); } -- cgit v1.2.3 From 9c2ddffa83353d608a24b5fdd0164a4a18d75916 Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Sun, 15 Jan 2017 00:11:16 +0100 Subject: Remove obsolete Lucene version constants. --- src/main/java/com/gitblit/service/LuceneService.java | 3 --- src/main/java/com/gitblit/tickets/TicketIndexer.java | 3 --- 2 files changed, 6 deletions(-) (limited to 'src') diff --git a/src/main/java/com/gitblit/service/LuceneService.java b/src/main/java/com/gitblit/service/LuceneService.java index 59b1ff24..f22cb5a5 100644 --- a/src/main/java/com/gitblit/service/LuceneService.java +++ b/src/main/java/com/gitblit/service/LuceneService.java @@ -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; @@ -125,8 +124,6 @@ public class LuceneService implements Runnable { 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; diff --git a/src/main/java/com/gitblit/tickets/TicketIndexer.java b/src/main/java/com/gitblit/tickets/TicketIndexer.java index 02af25ef..652323a4 100644 --- a/src/main/java/com/gitblit/tickets/TicketIndexer.java +++ b/src/main/java/com/gitblit/tickets/TicketIndexer.java @@ -49,7 +49,6 @@ 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.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -167,8 +166,6 @@ public class TicketIndexer { private final Logger log = LoggerFactory.getLogger(getClass()); - private final Version luceneVersion = Version.LUCENE_5_5_2; - private final File luceneDir; private IndexWriter writer; -- cgit v1.2.3 From 8130906c48dcd4886bb8b28a6c1055489b499140 Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Sat, 21 Jan 2017 18:05:53 +0100 Subject: Update link target to Lucene 5.5 query syntax, moving the link to the page. Update the link target to the query parser syntax page of the 5.5 version. Refactor the `LuceneSearchPage` to use an `ExternalLink` for the link to the lucene page, so that the link target is kept and updated in the Java code. Move the link out of the language files. This was way too cumbersome to update the link target (which is probably why no one ever did). The query help text is changed to contain a variable: `gb.queryHelp = here be some ${querySyntax} help`, which is replaced by Wicket with a link. The link text is a new lange file property: `gb.querySyntax`. --- .../com/gitblit/wicket/GitBlitWebApp.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_cs.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_de.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_es.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_fr.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_it.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_ja.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_ko.properties | 211 +++++++++++---------- .../com/gitblit/wicket/GitBlitWebApp_nl.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_no.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_pl.properties | 3 +- .../gitblit/wicket/GitBlitWebApp_pt_BR.properties | 3 +- .../gitblit/wicket/GitBlitWebApp_zh_CN.properties | 3 +- .../gitblit/wicket/GitBlitWebApp_zh_TW.properties | 3 +- .../com/gitblit/wicket/pages/LuceneSearchPage.html | 4 +- .../com/gitblit/wicket/pages/LuceneSearchPage.java | 4 + 16 files changed, 139 insertions(+), 119 deletions(-) (limited to 'src') diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 66101f4d..c46bd63d 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -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.

Please see Lucene Query Parser Syntax for details. +gb.queryHelp = Standard query syntax is supported.

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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_cs.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_cs.properties index dc159ea5..45eb428f 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_cs.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_cs.properties @@ -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.

Pod\u00edvejte se pros\u00edm na Lucene Query Parser Syntax pro detaily. +gb.queryHelp=Standardn\u00ed syntaxe dotaz\u016f je podporov\u00e1na.

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) diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties index eca3fd2a..9599f7eb 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties @@ -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.

Unter Lucene Query Parser Syntax finden Sie weitere Details. +gb.queryHelp = Standard Abfragesyntax wird unterst\u00fctzt.

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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties index 791b286e..fa08485a 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_es.properties @@ -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.

Por favor, lee el: Analizador sint\u00E1ctico de consultas de Lucene para m\u00E1s detalles. +gb.queryHelp = Se admite la sintaxis de consulta est\u00E1ndar.

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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties index d479b3d6..3e757120 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties @@ -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.

Se r\u00e9f\u00e9rer \u00e0 la Syntaxe de recherche Lucene pour plus de d\u00e9tails. +gb.queryHelp = La syntaxe Lucene standard est support\u00e9e.

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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties index 7230ec83..970496bb 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties @@ -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.

Si vedi Lucene Query Parser Syntax per ulteriori dettagli. +gb.queryHelp = La sintassi standard è supportata.

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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_ja.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_ja.properties index c8a2449f..36e21a7f 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_ja.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_ja.properties @@ -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

\u8a73\u7d30\u306f Lucene Query Parser Syntax \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

\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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties index 031ff8db..b4a675ce 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties @@ -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.

\uC790\uC138\uD55C \uAC83\uC744 \uC6D0\uD55C\uB2E4\uBA74 \uB8E8\uC2E0 \uCFFC\uB9AC \uD30C\uC11C \uBB38\uBC95 \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.

\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. \ No newline at end of file +gb.referencedByTicket = \uD2F0\uCF13\uC5D0 \uCC38\uC870\uB428. diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties index f71d67d7..41656e8a 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties @@ -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.

Zie aub Lucene Query Parser Syntax voor informatie. +gb.queryHelp = Standaard query syntax wordt ondersteund.

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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties index efc13a1e..a02a30f3 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties @@ -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.

Se Lucene Query Parser Syntax for mer info. +gb.queryHelp = Standard lucene sp\u00F8rringssyntaks st\u00F8ttes.

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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties index b00d1ff8..fee4b975 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pl.properties @@ -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.

Na stronie Lucene Query Parser Syntax dost\u0119pne s\u0105 dalsze szczeg\u00F3\u0142y. +gb.queryHelp = Standardowa sk\u0142adnia wyszukiwa\u0144 jest wspierana.

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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties index 4d2ea553..b573792f 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_pt_BR.properties @@ -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.

Por favor veja Lucene Query Parser Syntax para mais detalhes. +gb.queryHelp = Standard query syntax é suportada.

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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties index b5e4f658..c82e12fa 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties @@ -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.

\u8bf7\u67e5\u770b Lucene \u67e5\u8be2\u5904\u7406\u5668\u683c\u5f0f \u4ee5\u83b7\u53d6\u8be6\u7ec6\u5185\u5bb9\u3002 +gb.queryHelp = \u652f\u6301\u6807\u51c6\u67e5\u8be2\u683c\u5f0f.

\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 diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_TW.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_TW.properties index 157dd566..63106469 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_TW.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_TW.properties @@ -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.

\u8a73\u60c5\u8acb\u53c3\u8003 Lucene Query Parser Syntax +gb.queryHelp = \u652f\u63f4\u6a19\u6e96\u67e5\u8a62\u8a9e\u6cd5.

\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 diff --git a/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.html b/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.html index d62b7b22..a386f425 100644 --- a/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.html +++ b/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.html @@ -52,7 +52,9 @@

- + + +
diff --git a/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.java b/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.java index 1d81061e..a97d37a8 100644 --- a/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.java +++ b/src/main/java/com/gitblit/wicket/pages/LuceneSearchPage.java @@ -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("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 -- cgit v1.2.3 From 71e24e22cca3f85996b8a0d1951311b4592f2213 Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Sat, 21 Jan 2017 19:09:18 +0100 Subject: Replace deprecated BooleanQuery constructor with builder. Also replace deprecated `search` method with the one without a filter argument, since the filter isn't used anyhow. --- src/main/java/com/gitblit/service/LuceneService.java | 10 +++++----- src/main/java/com/gitblit/tickets/TicketIndexer.java | 18 ++++++++---------- 2 files changed, 13 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/main/java/com/gitblit/service/LuceneService.java b/src/main/java/com/gitblit/service/LuceneService.java index f22cb5a5..9b97ad5b 100644 --- a/src/main/java/com/gitblit/service/LuceneService.java +++ b/src/main/java/com/gitblit/service/LuceneService.java @@ -718,10 +718,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(); QueryParser qp = new QueryParser(FIELD_SUMMARY, analyzer); - query.add(qp.parse(q), Occur.MUST); + BooleanQuery query = new BooleanQuery.Builder().add(qp.parse(q), Occur.MUST).build(); IndexWriter writer = getIndexWriter(repositoryName); int numDocsBefore = writer.numDocs(); @@ -1028,15 +1027,15 @@ public class LuceneService implements Runnable { 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(FIELD_SUMMARY, analyzer); qp.setAllowLeadingWildcard(true); - query.add(qp.parse(text), Occur.SHOULD); + bldr.add(qp.parse(text), Occur.SHOULD); 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) { @@ -1054,6 +1053,7 @@ public class LuceneService implements Runnable { searcher = new IndexSearcher(reader); } + BooleanQuery query = bldr.build(); Query rewrittenQuery = searcher.rewrite(query); logger.debug(rewrittenQuery.toString()); diff --git a/src/main/java/com/gitblit/tickets/TicketIndexer.java b/src/main/java/com/gitblit/tickets/TicketIndexer.java index 652323a4..b765cc66 100644 --- a/src/main/java/com/gitblit/tickets/TicketIndexer.java +++ b/src/main/java/com/gitblit/tickets/TicketIndexer.java @@ -200,8 +200,7 @@ public class TicketIndexer { IndexWriter writer = getWriter(); StandardAnalyzer analyzer = new StandardAnalyzer(); QueryParser qp = new QueryParser(Lucene.rid.name(), analyzer); - BooleanQuery query = new BooleanQuery(); - query.add(qp.parse(repository.getRID()), Occur.MUST); + BooleanQuery query = new BooleanQuery.Builder().add(qp.parse(repository.getRID()), Occur.MUST).build(); int numDocsBefore = writer.numDocs(); writer.deleteDocuments(query); @@ -286,8 +285,7 @@ public class TicketIndexer { private boolean delete(String repository, long ticketId, IndexWriter writer) throws Exception { StandardAnalyzer analyzer = new StandardAnalyzer(); QueryParser qp = new QueryParser(Lucene.did.name(), analyzer); - BooleanQuery query = new BooleanQuery(); - query.add(qp.parse(StringUtils.getSHA1(repository + ticketId)), Occur.MUST); + BooleanQuery query = new BooleanQuery.Builder().add(qp.parse(StringUtils.getSHA1(repository + ticketId)), Occur.MUST).build(); int numDocsBefore = writer.numDocs(); writer.deleteDocuments(query); @@ -331,23 +329,23 @@ public class TicketIndexer { 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(Lucene.title.name(), analyzer); qp.setAllowLeadingWildcard(true); - query.add(qp.parse(text), Occur.SHOULD); + bldr.add(qp.parse(text), Occur.SHOULD); 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(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()); @@ -406,7 +404,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); -- cgit v1.2.3 From bf1b35aac29b6c0d5e918f00d99a0632e4925b51 Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Sun, 26 Feb 2017 18:44:02 +0100 Subject: Add DocValues to support sorting of ticket index fields. In order to support sorting, Lucene 5 needs DocValue fields in an index. So in order to make the ticket index work, i.e. show any tickets on the tickets page, the ticket index needs to be changed, adding a DocValues field. The DocValuesFields are implemented for the current index, which does not use multiple values for a field. Should at any time in the future an existing numeric field get multiple values stored in a document, then the index needs to know that and use SortedNumeric DocValues and SortFields instead. --- src/main/java/com/gitblit/tickets/TicketIndexer.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/main/java/com/gitblit/tickets/TicketIndexer.java b/src/main/java/com/gitblit/tickets/TicketIndexer.java index b765cc66..8aab74ba 100644 --- a/src/main/java/com/gitblit/tickets/TicketIndexer.java +++ b/src/main/java/com/gitblit/tickets/TicketIndexer.java @@ -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,6 +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.BytesRef; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -549,14 +552,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) { @@ -564,6 +570,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))); } /** -- cgit v1.2.3 From 71a27ddc781e0c2a684f747c794f8948c65cbf5c Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Sun, 5 Mar 2017 16:45:44 +0100 Subject: Introduce an index version for the ticket index In order to be able to update the index definition, the ticket index is assigned a version number, 2. This way the definiton can be updated and compatability with existing index files can be checked. The actual index is stored in a directory of name `indexVersion_codecVersion`. This wayit is veriy easy to check if an index of a certain version exists on the filesystem. It allows to have multiple indexes of different versions present, so that a downgrade of the software is possible without having to reindex again. Of coure, this is only possible if no new tickets were created since these would be missing in the old index. A new class `LuceneIndexStore` is introduced, which abstracts away the versioned index directory. The idea is, that this provides one place to keep the Lucene codec version and to allow to code compatibility rules into this class, so that older indices can still be used if they are compatible. --- .../java/com/gitblit/tickets/TicketIndexer.java | 18 +- .../java/com/gitblit/utils/LuceneIndexStore.java | 98 +++++++++ .../com/gitblit/utils/LuceneIndexStoreTest.java | 245 +++++++++++++++++++++ 3 files changed, 352 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/gitblit/utils/LuceneIndexStore.java create mode 100644 src/test/java/com/gitblit/utils/LuceneIndexStoreTest.java (limited to 'src') diff --git a/src/main/java/com/gitblit/tickets/TicketIndexer.java b/src/main/java/com/gitblit/tickets/TicketIndexer.java index 8aab74ba..bc08fc88 100644 --- a/src/main/java/com/gitblit/tickets/TicketIndexer.java +++ b/src/main/java/com/gitblit/tickets/TicketIndexer.java @@ -62,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; /** @@ -110,6 +110,8 @@ public class TicketIndexer { priority(Type.INT), severity(Type.INT); + final static int INDEX_VERSION = 2; + final Type fieldType; Lucene(Type fieldType) { @@ -169,14 +171,15 @@ public class TicketIndexer { private final Logger log = LoggerFactory.getLogger(getClass()); - 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(); } /** @@ -441,12 +444,9 @@ public class TicketIndexer { private IndexWriter getWriter() throws IOException { if (writer == null) { - Directory directory = FSDirectory.open(luceneDir.toPath()); - - if (!luceneDir.exists()) { - luceneDir.mkdirs(); - } + indexStore.create(); + Directory directory = FSDirectory.open(indexStore.getPath()); StandardAnalyzer analyzer = new StandardAnalyzer(); IndexWriterConfig config = new IndexWriterConfig(analyzer); config.setOpenMode(OpenMode.CREATE_OR_APPEND); diff --git a/src/main/java/com/gitblit/utils/LuceneIndexStore.java b/src/main/java/com/gitblit/utils/LuceneIndexStore.java new file mode 100644 index 00000000..0ccfd2e8 --- /dev/null +++ b/src/main/java/com/gitblit/utils/LuceneIndexStore.java @@ -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); + } + +} diff --git a/src/test/java/com/gitblit/utils/LuceneIndexStoreTest.java b/src/test/java/com/gitblit/utils/LuceneIndexStoreTest.java new file mode 100644 index 00000000..4d66c5dc --- /dev/null +++ b/src/test/java/com/gitblit/utils/LuceneIndexStoreTest.java @@ -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()); + + } + +} -- cgit v1.2.3 From f44f45a15e10a87bcb62a6a3a1bb0f7cbc282478 Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Sun, 5 Mar 2017 17:11:50 +0100 Subject: Use versioned index directories for repository indices. Change from the index version of a repository index being stored in a config file to also using index directories with the version in the name. For that, `LuceneRepoIndexStore` is added, which adds the fixed `lucene` part to the path. It also gives out the location of the `lucene.conf` file, which is now stored in the index directory. This way it is automatically deleted when the directory is deleted. I believe that it should also provide means to store branch aliases and tips, i.e. hide the config file completely. But this isn't implemented with this commit, the `LuceneService` is still aware that a config file is used. --- .../com/gitblit/service/LuceneRepoIndexStore.java | 55 +++++ .../java/com/gitblit/service/LuceneService.java | 65 ++--- .../gitblit/service/LuceneRepoIndexStoreTest.java | 267 +++++++++++++++++++++ 3 files changed, 339 insertions(+), 48 deletions(-) create mode 100644 src/main/java/com/gitblit/service/LuceneRepoIndexStore.java create mode 100644 src/test/java/com/gitblit/service/LuceneRepoIndexStoreTest.java (limited to 'src') diff --git a/src/main/java/com/gitblit/service/LuceneRepoIndexStore.java b/src/main/java/com/gitblit/service/LuceneRepoIndexStore.java new file mode 100644 index 00000000..ff7d0885 --- /dev/null +++ b/src/main/java/com/gitblit/service/LuceneRepoIndexStore.java @@ -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); + } + +} diff --git a/src/main/java/com/gitblit/service/LuceneService.java b/src/main/java/com/gitblit/service/LuceneService.java index 9b97ad5b..906a0b5e 100644 --- a/src/main/java/com/gitblit/service/LuceneService.java +++ b/src/main/java/com/gitblit/service/LuceneService.java @@ -117,10 +117,6 @@ 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"; @@ -290,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(); } /** @@ -383,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()); } @@ -615,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); @@ -844,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(); @@ -962,14 +934,11 @@ 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.toPath()); - if (indexWriter == null) { - if (!indexFolder.exists()) { - indexFolder.mkdirs(); - } + 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); diff --git a/src/test/java/com/gitblit/service/LuceneRepoIndexStoreTest.java b/src/test/java/com/gitblit/service/LuceneRepoIndexStoreTest.java new file mode 100644 index 00000000..baac3516 --- /dev/null +++ b/src/test/java/com/gitblit/service/LuceneRepoIndexStoreTest.java @@ -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()); + + } + + +} -- cgit v1.2.3 From 63dbdfda13daa78a26f1c2e77b0a4bfd5a35df8d Mon Sep 17 00:00:00 2001 From: Florian Zschocke Date: Sun, 5 Mar 2017 20:12:48 +0100 Subject: Reindex tickets on server start if no index exists Check if tickets need to be reindexed when the server starts. This is the case if no ticket index exists. In that case the ticket index is built. This is done during the start of the `ITicketService`. For this the interface of `ITicketService` needed to change. The `start` method was defined abstract and the specific ticket services had to implement it. None does any real starting stuff in it. The `start` method is now final. It calls a new abstract method `onStart` which the specific ticket services need to implement. In the existing implementations I just changed `start` to `onStart`. --- .../com/gitblit/tickets/BranchTicketService.java | 3 +- .../com/gitblit/tickets/FileTicketService.java | 3 +- .../java/com/gitblit/tickets/ITicketService.java | 43 ++++++++++++++++++---- .../com/gitblit/tickets/NullTicketService.java | 3 +- .../com/gitblit/tickets/RedisTicketService.java | 3 +- .../java/com/gitblit/tickets/TicketIndexer.java | 14 ++++++- .../java/com/gitblit/utils/LuceneIndexStore.java | 2 +- .../com/gitblit/tests/BranchTicketServiceTest.java | 2 +- .../com/gitblit/tests/FileTicketServiceTest.java | 2 +- .../com/gitblit/tests/RedisTicketServiceTest.java | 2 +- src/test/java/com/gitblit/tests/UITicketTest.java | 2 +- 11 files changed, 58 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/main/java/com/gitblit/tickets/BranchTicketService.java b/src/main/java/com/gitblit/tickets/BranchTicketService.java index 7bef435a..8430c546 100644 --- a/src/main/java/com/gitblit/tickets/BranchTicketService.java +++ b/src/main/java/com/gitblit/tickets/BranchTicketService.java @@ -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 diff --git a/src/main/java/com/gitblit/tickets/FileTicketService.java b/src/main/java/com/gitblit/tickets/FileTicketService.java index 1e82f0de..05670468 100644 --- a/src/main/java/com/gitblit/tickets/FileTicketService.java +++ b/src/main/java/com/gitblit/tickets/FileTicketService.java @@ -80,9 +80,8 @@ public class FileTicketService extends ITicketService { } @Override - public FileTicketService start() { + public void onStart() { log.info("{} started", getClass().getSimpleName()); - return this; } @Override diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java index 20b6505b..3252a603 100644 --- a/src/main/java/com/gitblit/tickets/ITicketService.java +++ b/src/main/java/com/gitblit/tickets/ITicketService.java @@ -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. diff --git a/src/main/java/com/gitblit/tickets/NullTicketService.java b/src/main/java/com/gitblit/tickets/NullTicketService.java index 3947b945..050c6990 100644 --- a/src/main/java/com/gitblit/tickets/NullTicketService.java +++ b/src/main/java/com/gitblit/tickets/NullTicketService.java @@ -61,9 +61,8 @@ public class NullTicketService extends ITicketService { } @Override - public NullTicketService start() { + public void onStart() { log.info("{} started", getClass().getSimpleName()); - return this; } @Override diff --git a/src/main/java/com/gitblit/tickets/RedisTicketService.java b/src/main/java/com/gitblit/tickets/RedisTicketService.java index 0f9ad174..4e632317 100644 --- a/src/main/java/com/gitblit/tickets/RedisTicketService.java +++ b/src/main/java/com/gitblit/tickets/RedisTicketService.java @@ -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 diff --git a/src/main/java/com/gitblit/tickets/TicketIndexer.java b/src/main/java/com/gitblit/tickets/TicketIndexer.java index bc08fc88..7c164487 100644 --- a/src/main/java/com/gitblit/tickets/TicketIndexer.java +++ b/src/main/java/com/gitblit/tickets/TicketIndexer.java @@ -226,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 * @@ -665,4 +677,4 @@ public class TicketIndexer { int i = Integer.parseInt(val); return i; } -} \ No newline at end of file +} diff --git a/src/main/java/com/gitblit/utils/LuceneIndexStore.java b/src/main/java/com/gitblit/utils/LuceneIndexStore.java index 0ccfd2e8..c05e2019 100644 --- a/src/main/java/com/gitblit/utils/LuceneIndexStore.java +++ b/src/main/java/com/gitblit/utils/LuceneIndexStore.java @@ -92,7 +92,7 @@ public class LuceneIndexStore { return indexFolder.exists() && indexFolder.isDirectory() && - (indexFolder.list().length > 1); + (indexFolder.list().length > 1); // Must have more than 'write.lock' } } diff --git a/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java b/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java index 0a5de196..0e9d8874 100644 --- a/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java +++ b/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java @@ -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, diff --git a/src/test/java/com/gitblit/tests/FileTicketServiceTest.java b/src/test/java/com/gitblit/tests/FileTicketServiceTest.java index 1fb2eed9..c4a63c41 100644 --- a/src/test/java/com/gitblit/tests/FileTicketServiceTest.java +++ b/src/test/java/com/gitblit/tests/FileTicketServiceTest.java @@ -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, diff --git a/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java b/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java index 48011ade..5f3cb94f 100644 --- a/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java +++ b/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java @@ -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, diff --git a/src/test/java/com/gitblit/tests/UITicketTest.java b/src/test/java/com/gitblit/tests/UITicketTest.java index 54aa1e1e..e89c32fc 100644 --- a/src/test/java/com/gitblit/tests/UITicketTest.java +++ b/src/test/java/com/gitblit/tests/UITicketTest.java @@ -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, -- cgit v1.2.3