From c1c1300a74e57d9a8bc6d2e1f079f048934ce9df Mon Sep 17 00:00:00 2001
From: Mathias Kinzler <mathias.kinzler@sap.com>
Date: Mon, 14 Jun 2010 18:03:30 +0200
Subject: [PATCH] Allow to read configured keys

Currently, there is no way to read the content
of the Git Configuration in a  way that would
allow to list all configured values generically.
This change extends the Config class in such a
way as to being able to get a list of sections and
to get a list of names for any given section or
subsection.
This is required in able to implement proper
configuration handling in EGit (show all the
content of a given configuration similar to
"git config -l").

Change-Id: Idd4bc47be18ed0e36b11be8c23c9c707159dc830
Signed-off-by: Mathias Kinzler <mathias.kinzler@sap.com>
---
 .../jgit/lib/RepositoryConfigTest.java        |  38 +++++++
 .../src/org/eclipse/jgit/lib/Config.java      | 101 ++++++++++++++++++
 2 files changed, 139 insertions(+)

diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java
index 6f8076f09..860d0d67f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java
@@ -49,6 +49,7 @@
 
 import java.util.Arrays;
 import java.util.LinkedList;
+import java.util.Set;
 
 import junit.framework.TestCase;
 
@@ -313,6 +314,43 @@ public void testUnsetSingleSection() throws ConfigInvalidException {
 				+ "  packedGitLimit = 14\n", c.toText());
 	}
 
+	public void test008_readSectionNames() throws ConfigInvalidException {
+		final Config c = parse("[a]\n [B]\n");
+		Set<String> sections = c.getSections();
+		assertTrue("Sections should contain \"a\"", sections.contains("a"));
+		assertTrue("Sections should contain \"b\"", sections.contains("b"));
+	}
+
+	public void test009_readNamesInSection() throws ConfigInvalidException {
+		String configString = "[core]\n" + "repositoryformatversion = 0\n"
+				+ "filemode = false\n" + "logallrefupdates = true\n";
+		final Config c = parse(configString);
+		Set<String> names = c.getNames("core");
+		assertEquals("Core section size", 3, names.size());
+		assertTrue("Core section should contain \"filemode\"", names
+				.contains("filemode"));
+	}
+
+	public void test010_readNamesInSubSection() throws ConfigInvalidException {
+		String configString = "[a \"sub1\"]\n"//
+				+ "x = 0\n" //
+				+ "y = false\n"//
+				+ "z = true\n"//
+				+ "[a \"sub2\"]\n"//
+				+ "a=0\n"//
+				+ "b=1\n";
+		final Config c = parse(configString);
+		Set<String> names = c.getNames("a", "sub1");
+		assertEquals("Subsection size", 3, names.size());
+		assertTrue("Subsection should contain \"x\"", names.contains("x"));
+		assertTrue("Subsection should contain \"y\"", names.contains("y"));
+		assertTrue("Subsection should contain \"z\"", names.contains("z"));
+		names = c.getNames("a", "sub2");
+		assertEquals("Subsection size", 2, names.size());
+		assertTrue("Subsection should contain \"a\"", names.contains("a"));
+		assertTrue("Subsection should contain \"b\"", names.contains("b"));
+	}
+
 	private void assertReadLong(long exp) throws ConfigInvalidException {
 		assertReadLong(exp, String.valueOf(exp));
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
index 7c5af1e64..ccb251691 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
@@ -371,6 +371,33 @@ public Set<String> getSubsections(final String section) {
 		return get(new SubsectionNames(section));
 	}
 
+	/**
+	 * @return the sections defined in this {@link Config}
+	 */
+	public Set<String> getSections() {
+		return get(new SectionNames());
+	}
+
+	/**
+	 * @param section
+	 *            the section
+	 * @return the list of names defined for this section
+	 */
+	public Set<String> getNames(String section) {
+		return getNames(section, null);
+	}
+
+	/**
+	 * @param section
+	 *            the section
+	 * @param subsection
+	 *            the subsection
+	 * @return the list of names defined for this subsection
+	 */
+	public Set<String> getNames(String section, String subsection) {
+		return get(new NamesInSection(section, subsection));
+	}
+
 	/**
 	 * Obtain a handle to a parsed set of configuration values.
 	 *
@@ -1077,6 +1104,80 @@ public Set<String> parse(Config cfg) {
 		}
 	}
 
+	private static class NamesInSection implements SectionParser<Set<String>> {
+		private final String section;
+
+		private final String subsection;
+
+		NamesInSection(final String sectionName, final String subSectionName) {
+			section = sectionName;
+			subsection = subSectionName;
+		}
+
+		@Override
+		public int hashCode() {
+			final int prime = 31;
+			int result = 1;
+			result = prime * result + section.hashCode();
+			result = prime * result
+					+ ((subsection == null) ? 0 : subsection.hashCode());
+			return result;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (getClass() != obj.getClass())
+				return false;
+			NamesInSection other = (NamesInSection) obj;
+			if (!section.equals(other.section))
+				return false;
+			if (subsection == null) {
+				if (other.subsection != null)
+					return false;
+			} else if (!subsection.equals(other.subsection))
+				return false;
+			return true;
+		}
+
+		public Set<String> parse(Config cfg) {
+			final Set<String> result = new HashSet<String>();
+			while (cfg != null) {
+				for (final Entry e : cfg.state.get().entryList) {
+					if (e.name != null
+							&& StringUtils.equalsIgnoreCase(e.section, section)) {
+						if (subsection == null && e.subsection == null)
+							result.add(StringUtils.toLowerCase(e.name));
+						else if (e.subsection != null
+								&& e.subsection.equals(subsection))
+							result.add(StringUtils.toLowerCase(e.name));
+
+					}
+				}
+				cfg = cfg.baseConfig;
+			}
+			return Collections.unmodifiableSet(result);
+		}
+	}
+
+	private static class SectionNames implements SectionParser<Set<String>> {
+		public Set<String> parse(Config cfg) {
+			final Set<String> result = new HashSet<String>();
+			while (cfg != null) {
+				for (final Entry e : cfg.state.get().entryList) {
+					if (e.section != null)
+						result.add(StringUtils.toLowerCase(e.section));
+				}
+				cfg = cfg.baseConfig;
+			}
+			return Collections.unmodifiableSet(result);
+		}
+	}
+
+
 	private static class State {
 		final List<Entry> entryList;
 
-- 
GitLab