import os from datetime import datetime from .git import GitWorkdir from .hg import HgWorkdir from .utils import do_ex from .utils import require_command from .utils import trace class GitWorkdirHgClient(GitWorkdir, HgWorkdir): COMMAND = "hg" @classmethod def from_potential_worktree(cls, wd): require_command(cls.COMMAND) root, err, ret = do_ex("hg root", wd) if ret: return return cls(root) def is_dirty(self): out, _, _ = self.do_ex("hg id -T '{dirty}'") return bool(out) def get_branch(self): branch, err, ret = self.do_ex("hg id -T {bookmarks}") if ret: trace("branch err", branch, err, ret) return return branch def get_head_date(self): date_part, err, ret = self.do_ex("hg log -r . -T {shortdate(date)}") if ret: trace("head date err", date_part, err, ret) return return datetime.strptime(date_part, r"%Y-%m-%d").date() def is_shallow(self): return False def fetch_shallow(self): pass def get_hg_node(self): node, _, ret = self.do_ex("hg log -r . -T {node}") if not ret: return node def _hg2git(self, hg_node): git_node = None with open(os.path.join(self.path, ".hg/git-mapfile")) as file: for line in file: if hg_node in line: git_node, hg_node = line.split() break return git_node def node(self): hg_node = self.get_hg_node() if hg_node is None: return git_node = self._hg2git(hg_node) if git_node is None: # trying again after hg -> git self.do_ex("hg gexport") git_node = self._hg2git(hg_node) if git_node is None: trace("Cannot get git node so we use hg node", hg_node) if hg_node == "0" * len(hg_node): # mimick Git behavior return None return hg_node return git_node[:7] def count_all_nodes(self): revs, _, _ = self.do_ex("hg log -r 'ancestors(.)' -T '.'") return len(revs) def default_describe(self): """ Tentative to reproduce the output of `git describe --dirty --tags --long --match *[0-9]*` """ hg_tags, _, ret = self.do_ex( [ "hg", "log", "-r", "(reverse(ancestors(.)) and tag(r're:[0-9]'))", "-T", "{tags}{if(tags, ' ', '')}", ] ) if ret: return None, None, None hg_tags = hg_tags.split() if not hg_tags: return None, None, None git_tags = {} with open(os.path.join(self.path, ".hg/git-tags")) as file: for line in file: node, tag = line.split() git_tags[tag] = node # find the first hg tag which is also a git tag for tag in hg_tags: if tag in git_tags: break out, _, ret = self.do_ex(["hg", "log", "-r", f"'{tag}'::.", "-T", "."]) if ret: return None, None, None distance = len(out) - 1 node = self.node() desc = f"{tag}-{distance}-g{node}" if self.is_dirty(): desc += "-dirty" return desc, None, 0