hggithub.py 5.45 KB
Newer Older
Alexandre Richardson's avatar
Alexandre Richardson committed
1
2
3
4
5
6
"""hggithub

Add some usefull command to work with github
"""
import os
import os.path as osp
7
from shutil import move
Alexandre Richardson's avatar
Alexandre Richardson committed
8
9
10
11

from mercurial import registrar, error
from mercurial.i18n import _

12
from subprocess import check_output, CalledProcessError, STDOUT
Alexandre Richardson's avatar
Alexandre Richardson committed
13
14
15
16
17

cmdtable = {}
command = registrar.command(cmdtable)


18
19
def cmd(description, *args, **kwargs):
    print(description)
20
21
    if "quiet" in kwargs:
        quiet = kwargs.pop("quiet")
22
23
24
25
    try:
        kwargs["stderr"] = STDOUT
        check_output(*args, **kwargs)
    except CalledProcessError as ex:
26
27
28
        if not quiet:
            print(ex.output).strip()
            print("Command exited with code %d" % ex.returncode)
29
30
31
        raise


Alexandre Richardson's avatar
Alexandre Richardson committed
32
def git_clone(path_url, destination):
Elouan Martinet's avatar
Elouan Martinet committed
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
    cmd(
        "Cloning Git fork repository", ["git", "clone", path_url, destination, "--bare"]
    )


def git_configure_upstream(git_repo, git_upstream_url):
    cmd(
        "Adding upstream remote",
        ["git", "remote", "add", "upstream", git_upstream_url],
        cwd=git_repo,
    )
    git_pull_master(git_repo)


def git_pull_master(git_repo):
    cmd(
        "Fetching upstream remote",
        ["git", "fetch", "upstream", "master:master"],
        cwd=git_repo,
    )
    cmd(
        "Pushing master branch to Git fork repository",
        ["git", "push", "-f", "origin", "master"],
        cwd=git_repo,
    )
Alexandre Richardson's avatar
Alexandre Richardson committed
58

Elouan Martinet's avatar
Elouan Martinet committed
59

Alexandre Richardson's avatar
Alexandre Richardson committed
60
def hg_clone(path, destination):
61
62
63
    cmd(
        "Creating Mercurial repository",
        ["hg", "clone", "--config", "phases.new-commit=draft", path, destination],
64
    )
65
    cmd("Publishing master bookmark", ["hg", "phase", "-p", "master"], cwd=destination)
Alexandre Richardson's avatar
Alexandre Richardson committed
66
67


68
def update_hgrc(hg_repo):
Elouan Martinet's avatar
Elouan Martinet committed
69
    hgrc_path = osp.join(hg_repo, ".hg", "hgrc")
70
71
72
73
74
75
76
77
78
79
    with open(hgrc_path, "w+") as fobj:
        fobj.write(
            """\
[paths]
default = .hg/git.git

[gitrepo]
gitrepo = .hg/git.git
"""
        )
Alexandre Richardson's avatar
Alexandre Richardson committed
80
81


82
83
84
85
86
87
88
89
def hg_pull():
    cmd(
        "Updating Mercurial repository",
        ["hg", "--config", "phases.new-commit=draft", "pull"],
    )
    cmd("Publishing master bookmark", ["hg", "phase", "-p", "master"])


Elouan Martinet's avatar
Elouan Martinet committed
90
def _ghclone(git_fork_url, git_upstream_url, destination):
91
92
    working_dir, project_name = osp.split(destination)
    git_repo = osp.abspath(osp.join(working_dir, ".%s.git" % project_name))
Alexandre Richardson's avatar
Alexandre Richardson committed
93
94
    if osp.isdir(destination):
        raise ValueError(
Elouan Martinet's avatar
Elouan Martinet committed
95
96
97
98
            "Destination directory {} for hg repository should not exist".format(
                destination
            )
        )
Elouan Martinet's avatar
Elouan Martinet committed
99
100
    git_clone(git_fork_url, git_repo)
    git_configure_upstream(git_repo, git_upstream_url)
101
102
103
104
    hg_clone(git_repo, destination)
    final_git_repo = osp.abspath(osp.join(destination, ".hg", "git.git"))
    move(git_repo, final_git_repo)
    update_hgrc(destination)
Alexandre Richardson's avatar
Alexandre Richardson committed
105
106


107
def _ghpull(git_repo):
108
109
110
    branches = check_output(
        ["git", "branch", "--format=%(refname:lstrip=2)"], cwd=git_repo
    )
Elouan Martinet's avatar
Elouan Martinet committed
111
    git_pull_master(git_repo)
112
    for branch in branches.splitlines():
Elouan Martinet's avatar
Elouan Martinet committed
113
        if branch != "master":
114
115
116
117
118
119
120
121
122
            try:
                cmd(
                    "Fetching branch %s from remote Git fork repository" % branch,
                    ["git", "fetch", "origin", "%s:%s" % (branch, branch)],
                    cwd=git_repo,
                    quiet=True,
                )
            except CalledProcessError:
                print("Couldn't fetch remote branch, ignoring")
123
    hg_pull()
Elouan Martinet's avatar
Elouan Martinet committed
124
125


126
def _ghpush(git_repo, bookmark):
Elouan Martinet's avatar
Elouan Martinet committed
127
128
    if bookmark == "master":
        raise ValueError("Cannot push master branch")
129
    cmd(
130
131
        "Pushing bookmark to local Git repository",
        ["hg", "push", "-B", bookmark, "-f"],
132
133
134
    )
    # TODO use --force-with-lease if possible
    cmd(
Elouan Martinet's avatar
Elouan Martinet committed
135
        "Pushing Git branch to Git fork repository",
Elouan Martinet's avatar
Elouan Martinet committed
136
137
138
        ["git", "push", "--set-upstream", "origin", bookmark, "-f"],
        cwd=git_repo,
    )
139
140


141
142
143
144
145
146
147
148
149
150
151
152
def _ghremote(git_repo, git_remote_url, git_branch, hg_bookmark):
    if hg_bookmark == "master":
        raise ValueError("Cannot replace master bookmark")
    cmd(
        "Fetching branch %s to %s from specified remote Git repository"
        % (git_branch, hg_bookmark),
        ["git", "fetch", git_remote_url, "%s:%s" % (git_branch, hg_bookmark)],
        cwd=git_repo,
    )
    hg_pull()


Elouan Martinet's avatar
Elouan Martinet committed
153
154
155
156
@command(
    "ghclone", [], _("git_fork_path git_upstream_path working_directory"), norepo=True
)
def ghclone(ui, git_fork_url, git_upstream_url, working_directory, **opts):
157
158
    """Prepare working directory to work with github"""
    try:
Elouan Martinet's avatar
Elouan Martinet committed
159
        _ghclone(git_fork_url, git_upstream_url, working_directory)
160
161
162
163
164
165
166
167
    except CalledProcessError:
        pass
    except ValueError as ex:
        print(ex)


@command("ghpull", [], _(""))
def ghpull(ui, repo, **opts):
168
    os.chdir(repo.root)
169
170
171
172
173
174
175
176
177
178
179
    """Prepare working directory to work with github"""
    git_repo = ui.config("gitrepo", "gitrepo")
    try:
        _ghpull(git_repo)
    except CalledProcessError:
        pass


@command("ghpush", [], _("bookmark"))
def ghpush(ui, repo, bookmark, **opts):
    """Prepare working directory to work with github"""
180
    os.chdir(repo.root)
181
182
183
184
185
    git_repo = ui.config("gitrepo", "gitrepo")
    try:
        _ghpush(git_repo, bookmark)
    except CalledProcessError:
        pass
Elouan Martinet's avatar
Elouan Martinet committed
186
187
    except ValueError as ex:
        print(ex)
188
189
190
191
192
193
194
195
196
197
198


@command("ghremote", [], _("git_remote_path git_branch hg_bookmark"))
def ghremote(ui, repo, git_remote_url, git_branch, hg_bookmark, **opts):
    """Pull remote branch from alternate Git repository"""
    os.chdir(repo.root)
    git_repo = ui.config("gitrepo", "gitrepo")
    try:
        _ghremote(git_repo, git_remote_url, git_branch, hg_bookmark)
    except CalledProcessError:
        pass