summaryrefslogtreecommitdiff
path: root/src/setuptools_scm/hg_git.py
blob: 843b44cc92bdc85ed1e684b5ed96b96b10f44273 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import os
from datetime import datetime

from .utils import trace, require_command, do_ex
from .git import GitWorkdir
from .hg import HgWorkdir


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:
            print(err)
            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 node(self):
        hg_node = self.get_hg_node()
        if hg_node is None:
            return

        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

        if git_node is None:
            # trying again after hg -> git
            self.do_ex("hg gexport")
            return self.node()

        return git_node[:7]

    def count_all_nodes(self):
        revs, _, _ = self.do_ex("hg log -r 'ancestors(.)' -T '.'")
        return len(revs) + 1

    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()

        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 " + 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