diff --git a/dulwich/config.py b/dulwich/config.py index 1a32cba7c..2bd10877c 100644 --- a/dulwich/config.py +++ b/dulwich/config.py @@ -780,9 +780,15 @@ def parse_submodules(config: ConfigFile) -> Iterator[Tuple[bytes, bytes, bytes]] for section in config.keys(): section_kind, section_name = section if section_kind == b"submodule": - sm_path = config.get(section, b"path") - sm_url = config.get(section, b"url") - yield (sm_path, sm_url, section_name) + try: + sm_path = config.get(section, b"path") + sm_url = config.get(section, b"url") + yield (sm_path, sm_url, section_name) + except KeyError: + # If either path or url is missing, just ignore this + # submodule entry and move on to the next one. This is + # how git itself handles malformed .gitmodule entries. + pass def iter_instead_of(config: Config, push: bool = False) -> Iterable[Tuple[str, str]]: diff --git a/dulwich/tests/test_config.py b/dulwich/tests/test_config.py index bae048eb8..a05047792 100644 --- a/dulwich/tests/test_config.py +++ b/dulwich/tests/test_config.py @@ -423,6 +423,31 @@ def testSubmodules(self): [submodule "core/lib"] \tpath = core/lib \turl = https://github.com/phhusson/QuasselC.git +""" + ) + ) + got = list(parse_submodules(cf)) + self.assertEqual( + [ + ( + b"core/lib", + b"https://github.com/phhusson/QuasselC.git", + b"core/lib", + ) + ], + got, + ) + + def testMalformedSubmodules(self): + cf = ConfigFile.from_file( + BytesIO( + b"""\ +[submodule "core/lib"] +\tpath = core/lib +\turl = https://github.com/phhusson/QuasselC.git + +[submodule "dulwich"] +\turl = https://github.com/jelmer/dulwich """ ) )