James Moger
2015-11-22 ed552ba47c02779c270ffd62841d6d1048dade70
commit | author | age
c6f3d0 1 /*
JM 2  * Copyright (c) 2013 by syntevo GmbH. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  o Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *
10  *  o Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  *  o Neither the name of syntevo GmbH nor the names of
15  *    its contributors may be used to endorse or promote products derived
16  *    from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 package com.syntevo.bugtraq;
31
f1f303 32 import java.io.File;
JM 33 import java.io.IOException;
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.HashSet;
37 import java.util.List;
38 import java.util.Set;
c6f3d0 39
f1f303 40 import org.eclipse.jgit.errors.ConfigInvalidException;
JM 41 import org.eclipse.jgit.lib.Config;
42 import org.eclipse.jgit.lib.Constants;
43 import org.eclipse.jgit.lib.FileMode;
44 import org.eclipse.jgit.lib.ObjectId;
45 import org.eclipse.jgit.lib.ObjectLoader;
46 import org.eclipse.jgit.lib.Ref;
47 import org.eclipse.jgit.lib.Repository;
48 import org.eclipse.jgit.revwalk.RevCommit;
49 import org.eclipse.jgit.revwalk.RevTree;
50 import org.eclipse.jgit.revwalk.RevWalk;
51 import org.eclipse.jgit.storage.file.FileBasedConfig;
52 import org.eclipse.jgit.treewalk.TreeWalk;
53 import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
54 import org.jetbrains.annotations.NotNull;
55 import org.jetbrains.annotations.Nullable;
c6f3d0 56
JM 57 public final class BugtraqConfig {
58
59     // Constants ==============================================================
60
61     private static final String DOT_GIT_BUGTRAQ = ".gitbugtraq";
206b4b 62     private static final String DOT_TGITCONFIG = ".tgitconfig";
c6f3d0 63
JM 64     private static final String BUGTRAQ = "bugtraq";
65
66     private static final String URL = "url";
67     private static final String ENABLED = "enabled";
206b4b 68     private static final String LOG_REGEX = "logregex";
JM 69     private static final String LOG_FILTERREGEX = "logfilterregex";
70     private static final String LOG_LINKREGEX = "loglinkregex";
71     private static final String LOG_LINKTEXT = "loglinktext";
c6f3d0 72
JM 73     // Static =================================================================
74
75     @Nullable
76     public static BugtraqConfig read(@NotNull Repository repository) throws IOException, ConfigInvalidException {
206b4b 77         Config baseConfig = getBaseConfig(repository, DOT_GIT_BUGTRAQ);
JM 78         if (baseConfig == null) {
79             baseConfig = getBaseConfig(repository, DOT_TGITCONFIG);
80         }
81
c6f3d0 82         final Set<String> allNames = new HashSet<String>();
f1f303 83         final Config config;
JM 84         try {
85             config = repository.getConfig();
86         }
87         catch (RuntimeException ex) {
88             final Throwable cause = ex.getCause();
89             if (cause instanceof IOException) {
90                 throw (IOException)cause;
91             }
92             throw ex;
93         }
206b4b 94         if (getString(null, URL, config, baseConfig) != null) {
JM 95             allNames.add(null);
96         }
97         else {
98             allNames.addAll(config.getSubsections(BUGTRAQ));
99             if (baseConfig != null) {
100                 allNames.addAll(baseConfig.getSubsections(BUGTRAQ));
101             }
c6f3d0 102         }
JM 103
104         final List<BugtraqEntry> entries = new ArrayList<BugtraqEntry>();
105         for (String name : allNames) {
106             final String url = getString(name, URL, config, baseConfig);
206b4b 107             if (url == null) {
JM 108                 continue;
109             }
110
c6f3d0 111             final String enabled = getString(name, ENABLED, config, baseConfig);
JM 112             if (enabled != null && !"true".equals(enabled)) {
113                 continue;
114             }
115
206b4b 116             String idRegex = getString(name, LOG_REGEX, config, baseConfig);
JM 117             if (idRegex == null) {
c6f3d0 118                 return null;
JM 119             }
120
206b4b 121             String filterRegex = getString(name, LOG_FILTERREGEX, config, baseConfig);
JM 122             final String linkRegex = getString(name, LOG_LINKREGEX, config, baseConfig);
123             if (filterRegex == null && linkRegex == null) {
124                 final String[] split = idRegex.split("\n", Integer.MAX_VALUE);
125                 if (split.length == 2) {
126                     // Compatibility with TortoiseGit
127                     filterRegex = split[0];
128                     idRegex = split[1];
c6f3d0 129                 }
206b4b 130                 else {
JM 131                     // Backwards compatibility with specification version < 0.3
132                     final List<String> logIdRegexs = new ArrayList<String>();
133                     for (int index = 1; index < Integer.MAX_VALUE; index++) {
134                         final String logIdRegexN = getString(name, LOG_REGEX + index, config, baseConfig);
135                         if (logIdRegexN == null) {
136                             break;
137                         }
c6f3d0 138
206b4b 139                         logIdRegexs.add(logIdRegexN);
JM 140                     }
141
142                     if (logIdRegexs.size() > 1) {
143                         throw new ConfigInvalidException("More than three " + LOG_REGEX + " entries found. This is not supported anymore since bugtraq version 0.3, use " + LOG_FILTERREGEX + " and " + LOG_LINKREGEX + " instead.");
144                     }
145                     else if (logIdRegexs.size() == 1) {
146                         filterRegex = idRegex;
147                         idRegex = logIdRegexs.get(0);
148                     }
149                 }
c6f3d0 150             }
JM 151
206b4b 152             final String linkText = getString(name, LOG_LINKTEXT, config, baseConfig);
JM 153             entries.add(new BugtraqEntry(url, idRegex, linkRegex, filterRegex, linkText));
c6f3d0 154         }
JM 155
156         if (entries.isEmpty()) {
157             return null;
158         }
159
160         return new BugtraqConfig(entries);
161     }
162
163     // Fields =================================================================
164
165     @NotNull
166     private final List<BugtraqEntry> entries;
167
168     // Setup ==================================================================
169
170     BugtraqConfig(@NotNull List<BugtraqEntry> entries) {
171         this.entries = entries;
172     }
173
174     // Accessing ==============================================================
175
176     @NotNull
177     public List<BugtraqEntry> getEntries() {
178         return Collections.unmodifiableList(entries);
179     }
180
181     // Utils ==================================================================
182
183     @Nullable
206b4b 184     private static Config getBaseConfig(@NotNull Repository repository, @NotNull String configFileName) throws IOException, ConfigInvalidException {
c6f3d0 185         final Config baseConfig;
JM 186         if (repository.isBare()) {
187             // read bugtraq config directly from the repository
188             String content = null;
189             RevWalk rw = new RevWalk(repository);
190             TreeWalk tw = new TreeWalk(repository);
206b4b 191             tw.setFilter(PathFilterGroup.createFromStrings(configFileName));
c6f3d0 192             try {
f1f303 193                 final Ref ref = repository.getRef(Constants.HEAD);
JM 194                 if (ref == null) {
195                     return null;
196                 }
197
198                 ObjectId headId = ref.getTarget().getObjectId();
199                 if (headId == null || ObjectId.zeroId().equals(headId)) {
200                     return null;
201                 }
c6f3d0 202                 RevCommit commit = rw.parseCommit(headId);
JM 203                 RevTree tree = commit.getTree();
204                 tw.reset(tree);
205                 while (tw.next()) {
206                     ObjectId entid = tw.getObjectId(0);
207                     FileMode entmode = tw.getFileMode(0);
5842db 208                     if (FileMode.REGULAR_FILE == entmode) {
JM 209                         ObjectLoader ldr = repository.open(entid, Constants.OBJ_BLOB);
210                         content = new String(ldr.getCachedBytes(), commit.getEncoding());
211                         break;
c6f3d0 212                     }
JM 213                 }
206b4b 214             }
JM 215             finally {
c6f3d0 216                 rw.dispose();
a1cee6 217                 tw.close();
c6f3d0 218             }
JM 219
220             if (content == null) {
221                 // config not found
222                 baseConfig = null;
223             }
5842db 224             else {
JM 225                 // parse the config
226                 Config config = new Config();
227                 config.fromText(content);
228                 baseConfig = config;
229             }
230         }
231         else {
c6f3d0 232             // read bugtraq config from work tree
206b4b 233             final File baseFile = new File(repository.getWorkTree(), configFileName);
c6f3d0 234             if (baseFile.isFile()) {
JM 235                 FileBasedConfig fileConfig = new FileBasedConfig(baseFile, repository.getFS());
236                 fileConfig.load();
237                 baseConfig = fileConfig;
238             }
239             else {
240                 baseConfig = null;
241             }
242         }
243         return baseConfig;
244     }
245
246     @Nullable
206b4b 247     private static String getString(@Nullable String subsection, @NotNull String key, @NotNull Config config, @Nullable Config baseConfig) {
c6f3d0 248         final String value = config.getString(BUGTRAQ, subsection, key);
JM 249         if (value != null) {
250             return trimMaybeNull(value);
251         }
252
253         if (baseConfig != null) {
254             return trimMaybeNull(baseConfig.getString(BUGTRAQ, subsection, key));
255         }
256
206b4b 257             return value;
JM 258         }
c6f3d0 259
JM 260     @Nullable
261     private static String trimMaybeNull(@Nullable String string) {
262         if (string == null) {
263             return null;
264         }
265
266         string = string.trim();
267         if (string.length() == 0) {
268             return null;
269         }
270
271         return string;
272     }
273 }