Use config file infrastructure for writing initial .git/config file.
authorJelmer Vernooij <jelmer@samba.org>
Mon, 26 Dec 2011 17:05:50 +0000 (18:05 +0100)
committerJelmer Vernooij <jelmer@samba.org>
Mon, 26 Dec 2011 17:05:50 +0000 (18:05 +0100)
dulwich/config.py
dulwich/repo.py
dulwich/tests/test_repository.py

index 682843c7eb4d5e2a4583b7c3b9fb6a8ed6428cb5..e14c7d8d057c26044f3a72a6611115219ee19888 100644 (file)
@@ -29,22 +29,90 @@ from dulwich.file import GitFile
 class Config(object):
     """A Git configuration."""
 
+    def get(self, name):
+        """Retrieve the contents of a configuration setting.
+        
+        :param name: Name of the setting, including section and 
+            possible subsection.
+        :return: Contents of the setting
+        :raise KeyError: if the value is not set
+        """
+        raise NotImplementedError(self.get)
+
+    def set(self, name, value):
+        """Set a configuration value.
+        
+        :param name: Name of the configuration value, including section
+            and optional subsection
+        :param: Value of the setting
+        """
+        raise NotImplementedError(self.set)
 
 
-class ConfigFile(Config):
-    """A Git configuration file, like .git/config or ~/.gitconfig."""
+class ConfigDict(Config):
+    """Git configuration stored in a dictionary."""
 
     def __init__(self):
-        """Create a new ConfigFile."""
+        """Create a new ConfigDict."""
+        self._values = {}
 
     def __eq__(self, other):
-        return isinstance(other, self.__class__)
+        return (
+            isinstance(other, self.__class__) and
+            other._values == self._values)
+
+    @classmethod
+    def _parse_setting(cls, name):
+        parts = name.split(".")
+        if len(parts) == 3:
+            return (parts[0], parts[1], parts[2])
+        else:
+            return (parts[0], None, parts[1])
+
+    def get(self, name):
+        (section, subsection, variable) = self._parse_setting(name)
+        if subsection is not None:
+            try:
+                return self._values[section][subsection][variable]
+            except KeyError:
+                pass
+        return self._values[section][None][variable]
+
+    def set(self, name, value):
+        (section, subsection, variable) = self._parse_setting(name)
+        self._values.setdefault(section, {}).setdefault(subsection, {})[variable] = value
+
+
+class ConfigFile(ConfigDict):
+    """A Git configuration file, like .git/config or ~/.gitconfig.
+    """
 
     @classmethod
     def from_file(cls, f):
         """Read configuration from a file-like object."""
         ret = cls()
-        # FIXME
+        section = None
+        setting = None
+        for lineno, line in enumerate(f.readlines()):
+            line = line.lstrip()
+            if setting is None:
+                if line[0] == "[" and line.rstrip()[-1] == "]":
+                    section = (line.strip()[1:-1], None)
+                    ret._values[section[0]] = {section[1]: {}}
+                    # FIXME: Parse section
+                elif "=" in line:
+                    setting, value = line.split("=", 1)
+                    if section is None:
+                        raise ValueError("setting %r without section" % line)
+                    setting = setting.strip()
+                    ret._values[section[0]][section[1]][setting] = ""
+                else:
+                    setting = line.strip()
+                    value = True
+            if setting is not None:
+                if section is None:
+                    raise ValueError("setting %r without section" % line)
+                ret._values[section[0]][section[1]][setting] += line
         return ret
 
     @classmethod
@@ -70,7 +138,14 @@ class ConfigFile(Config):
 
     def write_to_file(self, f):
         """Write configuration to a file-like object."""
-        # FIXME
+        for section_name, section in self._values.iteritems():
+            for subsection_name, subsection in section.iteritems():
+                if subsection_name is None:
+                    f.write("[%s]\n" % section_name)
+                else:
+                    f.write("[%s \"%s\"]\n" % (section_name, subsection_name))
+                for key, value in subsection.iteritems():
+                    f.write("%s = %s\n" % (key, value))
 
 
 class StackedConfig(Config):
@@ -106,3 +181,14 @@ class StackedConfig(Config):
                     continue
             backends.append(cf)
         return cls(backends)
+
+    def get(self, name):
+        for backend in self._backends:
+            try:
+                return backend.get(name)
+            except KeyError:
+                pass
+        raise KeyError(name)
+
+    def set(self, name, value):
+        raise NotImplementedError(self.set)
index f6a293ca094220e65fd3bcf6e5b109957a997a6c..81730c930539209131a96aa85f1a7d95c0faed59 100644 (file)
@@ -800,12 +800,16 @@ class BaseRepo(object):
 
     def _init_files(self, bare):
         """Initialize a default set of named files."""
+        from dulwich.config import ConfigFile
         self._put_named_file('description', "Unnamed repository")
-        self._put_named_file('config', ('[core]\n'
-                                        'repositoryformatversion = 0\n'
-                                        'filemode = true\n'
-                                        'bare = ' + str(bare).lower() + '\n'
-                                        'logallrefupdates = true\n'))
+        f = StringIO()
+        cf = ConfigFile()
+        cf.set("core.repositoryformatversion", "0")
+        cf.set("core.filemode", "true")
+        cf.set("core.bare", str(bare).lower())
+        cf.set("core.logallrefupdates", "true")
+        cf.write_to_file(f)
+        self._put_named_file('config', f.getvalue())
         self._put_named_file(os.path.join('info', 'exclude'), '')
 
     def get_named_file(self, path):
@@ -919,7 +923,7 @@ class BaseRepo(object):
     def get_config(self):
         from dulwich.config import ConfigFile
         try:
-            p = ConfigFile.from_file(os.path.join(self._controldir, 'config'))
+            p = ConfigFile.from_path(os.path.join(self._controldir, 'config'))
         except (IOError, OSError), e:
             if e.errno == errno.ENOENT:
                 return ConfigFile()
index 8d9d4813b69dcbdc98d1ae18f1e3e1cd4131938e..d40249ec298b28bfc068814136c5691aa1368b5e 100644 (file)
@@ -74,7 +74,8 @@ class CreateRepositoryTests(TestCase):
         self.assertFileContentsEqual('', repo, os.path.join('info', 'exclude'))
         self.assertFileContentsEqual(None, repo, 'nonexistent file')
         barestr = 'bare = %s' % str(expect_bare).lower()
-        self.assertTrue(barestr in repo.get_named_file('config').read())
+        config_text = repo.get_named_file('config').read()
+        self.assertTrue(barestr in config_text, "%r" % config_text)
 
     def test_create_disk_bare(self):
         tmp_dir = tempfile.mkdtemp()