annotate contrib/hg-relink @ 5483:0c43f87baba3 default tip

Fix file-changed-to-dir and dir-to-file commits (issue660). Allow adding to dirstate files that clash with previously existing but marked for removal. Protect from reintroducing clashes by revert. This change doesn't address related issues with update. Current workaround is to do "clean" update by manually removing conflicting files/dirs from working directory.
author Maxim Dounin <mdounin@mdounin.ru>
date Sat, 27 Oct 2007 16:27:55 +0400
parents 29eb88bd5c8d
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
4244
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
1 #!/usr/bin/env python
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
2 #
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
3 # Copyright (C) 2007 Brendan Cully <brendan@kublai.com>
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
4 #
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
5 # This software may be used and distributed according to the terms
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
6 # of the GNU General Public License, incorporated herein by reference.
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
7
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
8 import os, sys
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
9
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
10 class ConfigError(Exception): pass
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
11
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
12 def usage():
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
13 print """relink <source> <destination>
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
14 Recreate hard links between source and destination repositories"""
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
15
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
16 class Config:
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
17 def __init__(self, args):
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
18 if len(args) != 3:
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
19 raise ConfigError("wrong number of arguments")
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
20 self.src = os.path.abspath(args[1])
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
21 self.dst = os.path.abspath(args[2])
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
22 for d in (self.src, self.dst):
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
23 if not os.path.exists(os.path.join(d, '.hg')):
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
24 raise ConfigError("%s: not a mercurial repository" % d)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
25
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
26 def collect(src):
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
27 seplen = len(os.path.sep)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
28 candidates = []
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
29 for dirpath, dirnames, filenames in os.walk(src):
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
30 relpath = dirpath[len(src) + seplen:]
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
31 for filename in filenames:
4260
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
32 if not filename.endswith('.i'):
4244
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
33 continue
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
34 st = os.stat(os.path.join(dirpath, filename))
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
35 candidates.append((os.path.join(relpath, filename), st))
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
36
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
37 return candidates
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
38
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
39 def prune(candidates, dst):
4260
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
40 def getdatafile(path):
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
41 if not path.endswith('.i'):
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
42 return None, None
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
43 df = path[:-1] + 'd'
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
44 try:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
45 st = os.stat(df)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
46 except OSError:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
47 return None, None
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
48 return df, st
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
49
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
50 def linkfilter(dst, st):
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
51 try:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
52 ts = os.stat(dst)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
53 except OSError:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
54 # Destination doesn't have this file?
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
55 return False
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
56 if st.st_ino == ts.st_ino:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
57 return False
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
58 if st.st_dev != ts.st_dev:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
59 # No point in continuing
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
60 raise Exception('Source and destination are on different devices')
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
61 if st.st_size != ts.st_size:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
62 # TODO: compare revlog heads
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
63 return False
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
64 return st
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
65
4244
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
66 targets = []
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
67 for fn, st in candidates:
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
68 tgt = os.path.join(dst, fn)
4260
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
69 ts = linkfilter(tgt, st)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
70 if not ts:
4244
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
71 continue
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
72 targets.append((fn, ts.st_size))
4260
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
73 df, ts = getdatafile(tgt)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
74 if df:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
75 targets.append((fn[:-1] + 'd', ts.st_size))
4244
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
76
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
77 return targets
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
78
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
79 def relink(src, dst, files):
4260
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
80 def relinkfile(src, dst):
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
81 bak = dst + '.bak'
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
82 os.rename(dst, bak)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
83 try:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
84 os.link(src, dst)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
85 except OSError:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
86 os.rename(bak, dst)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
87 raise
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
88 os.remove(bak)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
89
4244
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
90 CHUNKLEN = 65536
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
91 relinked = 0
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
92 savedbytes = 0
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
93
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
94 for f, sz in files:
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
95 source = os.path.join(src, f)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
96 tgt = os.path.join(dst, f)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
97 sfp = file(source)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
98 dfp = file(tgt)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
99 sin = sfp.read(CHUNKLEN)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
100 while sin:
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
101 din = dfp.read(CHUNKLEN)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
102 if sin != din:
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
103 break
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
104 sin = sfp.read(CHUNKLEN)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
105 if sin:
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
106 continue
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
107 try:
4260
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
108 relinkfile(source, tgt)
4244
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
109 print 'Relinked %s' % f
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
110 relinked += 1
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
111 savedbytes += sz
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
112 except OSError, inst:
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
113 print '%s: %s' % (tgt, str(inst))
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
114
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
115 print 'Relinked %d files (%d bytes reclaimed)' % (relinked, savedbytes)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
116
4260
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
117 try:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
118 cfg = Config(sys.argv)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
119 except ConfigError, inst:
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
120 print str(inst)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
121 usage()
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
122 sys.exit(1)
29eb88bd5c8d hg-relink: do not compare .d files
Brendan Cully <brendan@kublai.com>
parents: 4244
diff changeset
123
4244
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
124 src = os.path.join(cfg.src, '.hg')
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
125 dst = os.path.join(cfg.dst, '.hg')
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
126 candidates = collect(src)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
127 targets = prune(candidates, dst)
7663780b55a7 Add hg-relink script to contrib
Brendan Cully <brendan@kublai.com>
parents:
diff changeset
128 relink(src, dst, targets)