Mercurial > hg > config
comparison python/hg-merge.py @ 207:7bad4b7281f2
add a file to merge hg repositories
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Mon, 13 Feb 2012 16:22:59 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
195:171bd3b71e84 | 207:7bad4b7281f2 |
---|---|
1 #!/usr/bin/env python | |
2 | |
3 """ | |
4 merge mercurial repositories | |
5 | |
6 Example: | |
7 hg-merge.py --master http://hg.mozilla.org/build/talos http://hg.mozilla.org/build/pageloader#talos/pageloader | |
8 """ | |
9 | |
10 import optparse | |
11 import os | |
12 import shutil | |
13 import subprocess | |
14 import sys | |
15 import tempfile | |
16 import urlparse | |
17 try: | |
18 from subprocess import check_call as call | |
19 except: | |
20 from subprocess import call | |
21 | |
22 def url2filename(url): | |
23 """gets a filename from a url""" | |
24 scheme, netloc, path, query, fragment = urlparse.urlsplit(url) | |
25 path = path.rstrip('/') | |
26 assert path and '/' in path | |
27 return path.split('/')[-1] | |
28 | |
29 def manifest(hgrepo): | |
30 """manifest of a local hg repository""" | |
31 process = subprocess.Popen(['hg', 'manifest'], cwd=hgrepo, stdout=subprocess.PIPE) | |
32 stdout, stderr = process.communicate() | |
33 assert not process.returncode | |
34 manifest = stdout.strip().splitlines() | |
35 return set(manifest) | |
36 | |
37 def merge(hgroot, repo, subpath=None): | |
38 """merge repo to hgroot at subpath (None for repository root)""" | |
39 | |
40 # get a manifest of the current repository | |
41 root_manifest = manifest(hgroot) | |
42 toplevel_contents = os.listdir(hgroot) | |
43 | |
44 # staging area | |
45 tempdir = tempfile.mkdtemp() | |
46 fd, tmpfile = tempfile.mkstemp() | |
47 os.close(fd) | |
48 | |
49 exception = None | |
50 try: | |
51 | |
52 # clone the repository to be merged in | |
53 call(['hg', 'clone', repo, tempdir]) | |
54 | |
55 # check manifest for conflicts | |
56 repo_manifest = manifest(tempdir) | |
57 assert repo_manifest, "Empty repository: %s" % repo | |
58 intersection = root_manifest.intersection(repo_manifest) | |
59 assert not intersection, "Overlap between %s and %s: %s" % (hgroot, repo, intersection) | |
60 | |
61 # create a bundle | |
62 call(['hg', 'bundle', tmpfile, '--all'], cwd=tempdir) | |
63 | |
64 # apply the bundle | |
65 call(['hg', 'unbundle', tmpfile], cwd=hgroot) | |
66 call(['hg', 'merge'], cwd=hgroot) | |
67 | |
68 if subpath: | |
69 # move the new files to their new locations | |
70 for item in repo_manifest: | |
71 path = os.path.join(subpath, item) | |
72 fullpath = os.path.join(hgroot, path) | |
73 assert not os.path.exists(fullpath), "%s already exists" % fullpath | |
74 subdirectory = os.path.dirname(fullpath) | |
75 if not os.path.exists(subdirectory): | |
76 os.makedirs(subdirectory) | |
77 call(['hg', 'mv', item, path], cwd=hgroot) | |
78 call(['hg', 'commit', '-m', 'merge %s to %s' % (repo, subpath)], cwd=hgroot) | |
79 else: | |
80 call(['hg', 'commit', '-m', 'merge in %s' % repo], cwd=hgroot) | |
81 | |
82 except Exception, exception: | |
83 pass # reraise on cleanup | |
84 | |
85 # cleanup | |
86 shutil.rmtree(tempdir) | |
87 os.remove(tmpfile) | |
88 if exception is not None: | |
89 raise exception | |
90 | |
91 def main(args=sys.argv[1:]): | |
92 | |
93 # parse command line options | |
94 usage = "%prog [options] http://hg.example.com/repository/path#destination/path [...]" | |
95 parser = optparse.OptionParser(usage=usage, description=__doc__) | |
96 parser.add_option('-m', '--master', dest='master', | |
97 help="use this as the master repository (new clone, otherwise use CWD)") | |
98 options, args = parser.parse_args(args) | |
99 if not args: | |
100 parser.print_help() | |
101 parser.exit() | |
102 | |
103 if options.master: | |
104 # clone the new repository | |
105 directory = url2filename(options.master) | |
106 if os.path.exists(directory): | |
107 shutil.rmtree(directory) | |
108 call(['hg', 'clone', options.master]) | |
109 hgroot = os.path.join(os.getcwd(), directory) | |
110 else: | |
111 # get the root of the repository | |
112 process = subprocess.Popen(['hg', 'root'], stdout=subprocess.PIPE) | |
113 hgroot, stderr = process.communicate() | |
114 hgroot = hgroot.strip() | |
115 if process.returncode: | |
116 sys.exit(1) | |
117 assert os.path.exists(hgroot) and os.path.isdir(hgroot), "%s not found" % hgroot | |
118 | |
119 # get the other repos to add | |
120 for repo in args: | |
121 subpath = None | |
122 if '#' in repo: | |
123 repo, subpath = repo.rsplit('#', 1) | |
124 merge(hgroot, repo, subpath) | |
125 | |
126 if __name__ == '__main__': | |
127 main() |