Kiln » Kiln Extensions
Clone URL:  
big-push.py
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
# Copyright (C) 2009-2010 Fog Creek Software. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. '''automatically push large repositories in chunks''' from mercurial import cmdutil, commands, hg, extensions from mercurial.i18n import _ max_push_size = 1000 def findoutgoing(repo, other): try: # Mercurial 1.6 and higher from mercurial import discovery return discovery.findoutgoing(repo, other, force=False) except ImportError: # Mercurial 1.5 and lower return repo.findoutgoing(other, force=False) def prepush(repo, other, force, revs): try: # Mercurial 1.6 and higher from mercurial import discovery return discovery.prepush(repo, other, force, revs, False) except ImportError: # Mercurial 1.5 and lower return repo.prepush(other, False, revs) def remoteui(repo, opts): if hasattr(cmdutil, 'remoteui'): # Mercurial 1.5 and lower return cmdutil.remoteui(repo, opts) else: # Mercurial 1.6 and higher return hg.remoteui(repo, opts) def bigpush(push_fn, ui, repo, dest=None, *files, **opts): '''Pushes this repository to a target repository. If this repository is small, behaves as the native push command. For large, remote repositories, the repository is pushed in chunks of 1000 changesets.''' if not opts.get('chunked'): return push_fn(ui, repo, dest, **opts) source, revs = parseurl(ui.expandpath(dest or 'default-push', dest or 'default')) other = hg.repository(remoteui(repo, opts), source) if hasattr(hg, 'addbranchrevs'): revs = hg.addbranchrevs(repo, other, revs, opts.get('rev'))[0] if revs: revs = [repo.lookup(rev) for rev in revs] if other.local(): return push_fn(ui, repo, dest, **opts) ui.status(_('pushing to %s\n') % other.path) outgoing = findoutgoing(repo, other) if outgoing: outgoing = repo.changelog.nodesbetween(outgoing, revs)[0] # if the push will create multiple heads and isn't forced, fail now # (prepush prints an error message, so we can just exit) if not opts.get('force') and not opts.get('new_branch') and None == prepush(repo, other, False, revs)[0]: return try: while len(outgoing) > 0: ui.debug('start: %d to push\n' % len(outgoing)) current_push_size = min(max_push_size, len(outgoing)) ui.debug('pushing: %d\n' % current_push_size) # force the push, because we checked above that by the time the whole push is done, we'll have merged back to one head remote_heads = repo.push(other, force=True, revs=outgoing[:current_push_size]) if remote_heads: # push succeeded outgoing = outgoing[current_push_size:] current_push_size = max_push_size ui.debug('pushed %d ok\n' % current_push_size) else: # push failed; try again with a smaller size current_push_size /= 10 ui.debug('failed, trying %d\n' % current_push_size) if current_push_size == 0: raise UnpushableChangesetError except UnpushableChangesetError: ui.status(_('unable to push changeset %s\n') % outgoing[0]) ui.debug('done\n') def parseurl(source): '''wrap hg.parseurl to work on 1.3 -> 1.5''' return hg.parseurl(source, None)[:2] def uisetup(ui): push_cmd = extensions.wrapcommand(commands.table, 'push', bigpush) push_cmd[1].extend([('', 'chunked', None, 'push large repository in chunks')]) class UnpushableChangesetError(Exception): pass