def _clone_submodules(cls, repo: Repo) -> None: """ Helper method to identify configured submodules and clone them recursively. """ repo_root = Path(repo.path) modules_config = repo_root.joinpath(".gitmodules") if modules_config.exists(): config = ConfigFile.from_path(modules_config) url: bytes path: bytes submodules = parse_submodules(config) # type: ignore[no-untyped-call] for path, url, _ in submodules: path_relative = Path(path.decode("utf-8")) path_absolute = repo_root.joinpath(path_relative) source_root = path_absolute.parent source_root.mkdir(parents=True, exist_ok=True) with repo: revision = repo.open_index()[path].sha.decode("utf-8") cls.clone( url=url.decode("utf-8"), source_root=source_root, name=path_relative.name, revision=revision, clean=path_absolute.exists() and not path_absolute.joinpath(".git").is_dir(), )
def neglect_submodule_templates(project_root, template_list): template_dict = {} # one template object per path. for template in template_list: template_dict[template.template_path] = template for template_descendent in template.descendents: template_dict[ template_descendent.template_path] = template_descendent # Removing those within a submodule. submodule_path_prefixes = [] try: gitmodule_config = ConfigFile.from_path( Path(project_root / ".gitmodules")) except FileNotFoundError: return template_list for submodule_path, _, _ in parse_submodules(gitmodule_config): submodule_path_prefixes.append( Path(project_root / submodule_path.decode("utf-8"))) finalized_templates = [] for template_obj in list(template_dict.values()): gitmodule_template = False for gm_path in submodule_path_prefixes: if gm_path in template_obj.template_path.parents: gitmodule_template = True if not gitmodule_template: finalized_templates.append(template_obj) return finalized_templates
def testSubmodules(self): cf = ConfigFile.from_file(BytesIO(b"""\ [submodule "core/lib"] path = core/lib url = 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 testSubmodules(self): cf = ConfigFile.from_file(BytesIO(b"""\ [submodule "core/lib"] path = core/lib url = 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 parse_gitmodules(git, tree_obj): """Parse .gitmodules from a git tree specified by tree_obj Returns a list of tuples (submodule path, url, name), where name is hgutil.urlreq.quoted part of the section's name Raises KeyError if no modules exist, or ValueError if they're invalid """ unused_mode, gitmodules_sha = tree_obj[b'.gitmodules'] gitmodules_content = git[gitmodules_sha].data with io.BytesIO(gitmodules_content) as fp: cfg = dul_config.ConfigFile.from_file(fp) return dul_config.parse_submodules(cfg)
def _find_submodules(self) -> Dict[str, "PathInfo"]: """Return dict mapping submodule names to submodule paths. Submodule paths will be relative to Git repo root. """ from dulwich.config import ConfigFile, parse_submodules submodules: Dict[str, "PathInfo"] = {} config_path = os.path.join(self.root_dir, ".gitmodules") if os.path.isfile(config_path): config = ConfigFile.from_path(config_path) for path, _url, section in parse_submodules(config): submodules[os.fsdecode(section)] = PathInfo(os.fsdecode(path)) return submodules
def _recurse_submodules(self, path: Path, parent_url): gitmodule_path = path / ".gitmodules" if not gitmodule_path.is_file(): return conf = ConfigFile.from_path(str(gitmodule_path)) for sub_path, url, name in parse_submodules(conf): sub_path = sub_path.decode("utf-8") url = url.decode("utf-8") name = name.decode("utf-8") if not (path / sub_path).is_dir(): (path / sub_path).mkdir(parents=True) # bizarre process here, but I don't know how else to get the sha for the # submodule... sha = None try: porcelain.get_object_by_path(str(path), sub_path) except KeyError as e: sha = e.args[0].decode("utf-8") if not sha: raise ValueError(f"Could not find sha for submodule {name}") if url.startswith("../"): base_url = parent_url for _ in range(url.count("../")): base_url = "/".join(base_url.split("/")[:-1]) url = base_url + "/" + url.replace("../", "") outp = BytesIO() if not (path / sub_path / ".git").is_dir(): LOG.info(f"fetching git submodule {url}") porcelain.clone( url, str(path / sub_path), checkout=sha, errstream=outp, outstream=outp, ) LOG.debug(outp.getvalue().decode("utf-8")) self._recurse_submodules((path / sub_path), url)