| | |
| | | */ |
| | | package com.syntevo.bugtraq; |
| | | |
| | | import java.io.ByteArrayOutputStream; |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.HashSet; |
| | |
| | | import org.eclipse.jgit.lib.FileMode; |
| | | import org.eclipse.jgit.lib.ObjectId; |
| | | import org.eclipse.jgit.lib.ObjectLoader; |
| | | import org.eclipse.jgit.lib.Ref; |
| | | import org.eclipse.jgit.lib.Repository; |
| | | import org.eclipse.jgit.lib.StoredConfig; |
| | | import org.eclipse.jgit.revwalk.RevCommit; |
| | | import org.eclipse.jgit.revwalk.RevObject; |
| | | import org.eclipse.jgit.revwalk.RevTree; |
| | | import org.eclipse.jgit.revwalk.RevWalk; |
| | | import org.eclipse.jgit.storage.file.FileBasedConfig; |
| | |
| | | // Constants ============================================================== |
| | | |
| | | private static final String DOT_GIT_BUGTRAQ = ".gitbugtraq"; |
| | | private static final String DOT_TGITCONFIG = ".tgitconfig"; |
| | | |
| | | private static final String BUGTRAQ = "bugtraq"; |
| | | |
| | | private static final String URL = "url"; |
| | | private static final String ENABLED = "enabled"; |
| | | private static final String LOG_REGEX = "logRegex"; |
| | | private static final String LOG_REGEX = "logregex"; |
| | | private static final String LOG_FILTERREGEX = "logfilterregex"; |
| | | private static final String LOG_LINKREGEX = "loglinkregex"; |
| | | private static final String LOG_LINKTEXT = "loglinktext"; |
| | | |
| | | // Static ================================================================= |
| | | |
| | | @Nullable |
| | | public static BugtraqConfig read(@NotNull Repository repository) throws IOException, ConfigInvalidException { |
| | | final Config baseConfig = getBaseConfig(repository); |
| | | Config baseConfig = getBaseConfig(repository, DOT_GIT_BUGTRAQ); |
| | | if (baseConfig == null) { |
| | | baseConfig = getBaseConfig(repository, DOT_TGITCONFIG); |
| | | } |
| | | |
| | | final Set<String> allNames = new HashSet<String>(); |
| | | final Config config = repository.getConfig(); |
| | | allNames.addAll(config.getSubsections(BUGTRAQ)); |
| | | if (baseConfig != null) { |
| | | allNames.addAll(baseConfig.getSubsections(BUGTRAQ)); |
| | | final Config config; |
| | | try { |
| | | config = repository.getConfig(); |
| | | } |
| | | catch (RuntimeException ex) { |
| | | final Throwable cause = ex.getCause(); |
| | | if (cause instanceof IOException) { |
| | | throw (IOException)cause; |
| | | } |
| | | throw ex; |
| | | } |
| | | if (getString(null, URL, config, baseConfig) != null) { |
| | | allNames.add(null); |
| | | } |
| | | else { |
| | | allNames.addAll(config.getSubsections(BUGTRAQ)); |
| | | if (baseConfig != null) { |
| | | allNames.addAll(baseConfig.getSubsections(BUGTRAQ)); |
| | | } |
| | | } |
| | | |
| | | final List<BugtraqEntry> entries = new ArrayList<BugtraqEntry>(); |
| | | for (String name : allNames) { |
| | | final String url = getString(name, URL, config, baseConfig); |
| | | if (url == null) { |
| | | continue; |
| | | } |
| | | |
| | | final String enabled = getString(name, ENABLED, config, baseConfig); |
| | | if (enabled != null && !"true".equals(enabled)) { |
| | | continue; |
| | | } |
| | | |
| | | final String logIdRegex = getString(name, LOG_REGEX, config, baseConfig); |
| | | if (url == null || logIdRegex == null) { |
| | | String idRegex = getString(name, LOG_REGEX, config, baseConfig); |
| | | if (idRegex == null) { |
| | | return null; |
| | | } |
| | | |
| | | final List<String> logIdRegexs = new ArrayList<String>(); |
| | | logIdRegexs.add(logIdRegex); |
| | | |
| | | for (int index = 1; index < Integer.MAX_VALUE; index++) { |
| | | final String logIdRegexN = getString(name, LOG_REGEX + index, config, baseConfig); |
| | | if (logIdRegexN == null) { |
| | | break; |
| | | String filterRegex = getString(name, LOG_FILTERREGEX, config, baseConfig); |
| | | final String linkRegex = getString(name, LOG_LINKREGEX, config, baseConfig); |
| | | if (filterRegex == null && linkRegex == null) { |
| | | final String[] split = idRegex.split("\n", Integer.MAX_VALUE); |
| | | if (split.length == 2) { |
| | | // Compatibility with TortoiseGit |
| | | filterRegex = split[0]; |
| | | idRegex = split[1]; |
| | | } |
| | | else { |
| | | // Backwards compatibility with specification version < 0.3 |
| | | final List<String> logIdRegexs = new ArrayList<String>(); |
| | | for (int index = 1; index < Integer.MAX_VALUE; index++) { |
| | | final String logIdRegexN = getString(name, LOG_REGEX + index, config, baseConfig); |
| | | if (logIdRegexN == null) { |
| | | break; |
| | | } |
| | | |
| | | logIdRegexs.add(logIdRegexN); |
| | | logIdRegexs.add(logIdRegexN); |
| | | } |
| | | |
| | | if (logIdRegexs.size() > 1) { |
| | | 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."); |
| | | } |
| | | else if (logIdRegexs.size() == 1) { |
| | | filterRegex = idRegex; |
| | | idRegex = logIdRegexs.get(0); |
| | | } |
| | | } |
| | | } |
| | | |
| | | entries.add(new BugtraqEntry(url, logIdRegexs)); |
| | | final String linkText = getString(name, LOG_LINKTEXT, config, baseConfig); |
| | | entries.add(new BugtraqEntry(url, idRegex, linkRegex, filterRegex, linkText)); |
| | | } |
| | | |
| | | if (entries.isEmpty()) { |
| | |
| | | // Utils ================================================================== |
| | | |
| | | @Nullable |
| | | private static Config getBaseConfig(Repository repository) throws IOException, ConfigInvalidException { |
| | | private static Config getBaseConfig(@NotNull Repository repository, @NotNull String configFileName) throws IOException, ConfigInvalidException { |
| | | final Config baseConfig; |
| | | if (repository.isBare()) { |
| | | // read bugtraq config directly from the repository |
| | | String content = null; |
| | | String head = repository.getFullBranch(); |
| | | RevWalk rw = new RevWalk(repository); |
| | | TreeWalk tw = new TreeWalk(repository); |
| | | tw.setFilter(PathFilterGroup.createFromStrings(DOT_GIT_BUGTRAQ)); |
| | | tw.setFilter(PathFilterGroup.createFromStrings(configFileName)); |
| | | try { |
| | | ObjectId headId = repository.resolve(head); |
| | | final Ref ref = repository.getRef(Constants.HEAD); |
| | | if (ref == null) { |
| | | return null; |
| | | } |
| | | |
| | | ObjectId headId = ref.getTarget().getObjectId(); |
| | | if (headId == null || ObjectId.zeroId().equals(headId)) { |
| | | return null; |
| | | } |
| | | RevCommit commit = rw.parseCommit(headId); |
| | | RevTree tree = commit.getTree(); |
| | | tw.reset(tree); |
| | | while (tw.next()) { |
| | | if (tw.isSubtree()) { |
| | | tw.enterSubtree(); |
| | | continue; |
| | | } |
| | | ObjectId entid = tw.getObjectId(0); |
| | | FileMode entmode = tw.getFileMode(0); |
| | | if (entmode == FileMode.REGULAR_FILE) { |
| | | RevObject ro = rw.lookupAny(entid, entmode.getObjectType()); |
| | | rw.parseBody(ro); |
| | | ByteArrayOutputStream os = new ByteArrayOutputStream(); |
| | | ObjectLoader ldr = repository.open(ro.getId(), Constants.OBJ_BLOB); |
| | | byte[] tmp = new byte[4096]; |
| | | InputStream in = ldr.openStream(); |
| | | int n; |
| | | while ((n = in.read(tmp)) > 0) { |
| | | os.write(tmp, 0, n); |
| | | } |
| | | in.close(); |
| | | content = new String(os.toByteArray(), commit.getEncoding()); |
| | | if (FileMode.REGULAR_FILE == entmode) { |
| | | ObjectLoader ldr = repository.open(entid, Constants.OBJ_BLOB); |
| | | content = new String(ldr.getCachedBytes(), commit.getEncoding()); |
| | | break; |
| | | } |
| | | } |
| | | } finally { |
| | | } |
| | | finally { |
| | | rw.dispose(); |
| | | tw.release(); |
| | | tw.close(); |
| | | } |
| | | |
| | | if (content == null) { |
| | | // config not found |
| | | baseConfig = null; |
| | | } else { |
| | | // parse the config |
| | | Config cfg = new Config(); |
| | | cfg.fromText(content); |
| | | baseConfig = new StoredConfig(cfg) { |
| | | @Override |
| | | public void save() throws IOException { |
| | | } |
| | | |
| | | @Override |
| | | public void load() throws IOException, ConfigInvalidException { |
| | | } |
| | | }; |
| | | } |
| | | } else { |
| | | else { |
| | | // parse the config |
| | | Config config = new Config(); |
| | | config.fromText(content); |
| | | baseConfig = config; |
| | | } |
| | | } |
| | | else { |
| | | // read bugtraq config from work tree |
| | | final File baseFile = new File(repository.getWorkTree(), DOT_GIT_BUGTRAQ); |
| | | final File baseFile = new File(repository.getWorkTree(), configFileName); |
| | | if (baseFile.isFile()) { |
| | | FileBasedConfig fileConfig = new FileBasedConfig(baseFile, repository.getFS()); |
| | | fileConfig.load(); |
| | |
| | | } |
| | | |
| | | @Nullable |
| | | private static String getString(@NotNull String subsection, @NotNull String key, @NotNull Config config, @Nullable Config baseConfig) { |
| | | private static String getString(@Nullable String subsection, @NotNull String key, @NotNull Config config, @Nullable Config baseConfig) { |
| | | final String value = config.getString(BUGTRAQ, subsection, key); |
| | | if (value != null) { |
| | | return trimMaybeNull(value); |
| | |
| | | return trimMaybeNull(baseConfig.getString(BUGTRAQ, subsection, key)); |
| | | } |
| | | |
| | | return value; |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | @Nullable |
| | | private static String trimMaybeNull(@Nullable String string) { |