##// END OF EJS Templates
Fix income/pull with bundle and -R (issue 820)....
Peter Arrenbrecht -
r5664:da72b4d2 default
parent child Browse files
Show More
@@ -0,0 +1,84 b''
1 #!/bin/sh
2
3 echo "[extensions]" >> $HGRCPATH
4 echo "mq=" >> $HGRCPATH
5 echo "[defaults]" >> $HGRCPATH
6 echo "log = --template \"{rev}: {desc}\\n\"" >> $HGRCPATH
7 echo "heads = --template \"{rev}: {desc}\\n\"" >> $HGRCPATH
8 echo "incoming = --template \"{rev}: {desc}\\n\"" >> $HGRCPATH
9
10 echo "====== .hgrc"
11 cat $HGRCPATH
12
13 echo "====== Setup main"
14 hg init base
15 cd base
16 echo "One" > one
17 hg add
18 hg ci -m "main: one added."
19 echo "++" >> one
20 hg ci -m "main: one updated."
21
22 echo "====== Bundle main"
23 hg bundle --base=null ../main.hg
24 cd ..
25
26 echo "====== Incoming to fresh repo"
27 hg init fresh
28 echo ">> hg -R fresh incoming main.hg"
29 hg -R fresh incoming main.hg
30 echo ">> hg -R fresh incoming bundle:fresh+main.hg"
31 hg -R fresh incoming bundle:fresh+main.hg
32
33
34 echo "====== Setup queue"
35 cd base
36 hg qinit -c
37 hg qnew -m "patch: two added." two.patch
38 echo two > two
39 hg add
40 hg qrefresh
41 hg qcommit -m "queue: two.patch added."
42 hg qpop -a
43
44 echo "====== Bundle queue"
45 hg -R .hg/patches bundle --base=null ../queue.hgq
46 cd ..
47
48
49 echo "====== Clone base"
50 hg clone base copy
51 cd copy
52 hg qinit -c
53
54 echo "====== Incoming queue bundle"
55 echo ">> hg -R .hg/patches incoming ../queue.hgq"
56 hg -R .hg/patches incoming ../queue.hgq
57
58 echo "====== Pull queue bundle"
59 echo ">> hg -R .hg/patches pull --update ../queue.hgq"
60 hg -R .hg/patches pull --update ../queue.hgq
61 echo ">> hg -R .hg/patches heads"
62 hg -R .hg/patches heads
63 echo ">> hg -R .hg/patches log"
64 hg -R .hg/patches log
65 echo ">> hg qseries"
66 hg qseries
67 cd ..
68
69
70 echo "====== Clone base again"
71 hg clone base copy2
72 cd copy2
73 hg qinit -c
74
75 echo "====== Unbundle queue bundle"
76 echo ">> hg -R .hg/patches unbundle --update ../queue.hgq"
77 hg -R .hg/patches unbundle --update ../queue.hgq
78 echo ">> hg -R .hg/patches heads"
79 hg -R .hg/patches heads
80 echo ">> hg -R .hg/patches log"
81 hg -R .hg/patches log
82 echo ">> hg qseries"
83 hg qseries
84 cd ..
@@ -0,0 +1,68 b''
1 ====== .hgrc
2 [ui]
3 slash = True
4 [defaults]
5 backout = -d "0 0"
6 commit = -d "0 0"
7 debugrawcommit = -d "0 0"
8 tag = -d "0 0"
9 [extensions]
10 mq=
11 [defaults]
12 log = --template "{rev}: {desc}\n"
13 heads = --template "{rev}: {desc}\n"
14 incoming = --template "{rev}: {desc}\n"
15 ====== Setup main
16 adding one
17 ====== Bundle main
18 ====== Incoming to fresh repo
19 >> hg -R fresh incoming main.hg
20 comparing with main.hg
21 0: main: one added.
22 1: main: one updated.
23 >> hg -R fresh incoming bundle:fresh+main.hg
24 comparing with bundle:fresh+main.hg
25 0: main: one added.
26 1: main: one updated.
27 ====== Setup queue
28 adding two
29 Patch queue now empty
30 ====== Bundle queue
31 ====== Clone base
32 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
33 ====== Incoming queue bundle
34 >> hg -R .hg/patches incoming ../queue.hgq
35 comparing with ../queue.hgq
36 0: queue: two.patch added.
37 ====== Pull queue bundle
38 >> hg -R .hg/patches pull --update ../queue.hgq
39 pulling from ../queue.hgq
40 requesting all changes
41 adding changesets
42 adding manifests
43 adding file changes
44 added 1 changesets with 3 changes to 3 files
45 merging series
46 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
47 >> hg -R .hg/patches heads
48 0: queue: two.patch added.
49 >> hg -R .hg/patches log
50 0: queue: two.patch added.
51 >> hg qseries
52 two.patch
53 ====== Clone base again
54 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
55 ====== Unbundle queue bundle
56 >> hg -R .hg/patches unbundle --update ../queue.hgq
57 adding changesets
58 adding manifests
59 adding file changes
60 added 1 changesets with 3 changes to 3 files
61 merging series
62 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
63 >> hg -R .hg/patches heads
64 0: queue: two.patch added.
65 >> hg -R .hg/patches log
66 0: queue: two.patch added.
67 >> hg qseries
68 two.patch
@@ -1,269 +1,280 b''
1 1 """
2 2 bundlerepo.py - repository class for viewing uncompressed bundles
3 3
4 4 This provides a read-only repository interface to bundles as if
5 5 they were part of the actual repository.
6 6
7 7 Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
8 8
9 9 This software may be used and distributed according to the terms
10 10 of the GNU General Public License, incorporated herein by reference.
11 11 """
12 12
13 13 from node import *
14 14 from i18n import _
15 15 import changegroup, util, os, struct, bz2, tempfile, mdiff
16 16 import localrepo, changelog, manifest, filelog, revlog
17 17
18 18 class bundlerevlog(revlog.revlog):
19 19 def __init__(self, opener, indexfile, bundlefile,
20 20 linkmapper=None):
21 21 # How it works:
22 22 # to retrieve a revision, we need to know the offset of
23 23 # the revision in the bundlefile (an opened file).
24 24 #
25 25 # We store this offset in the index (start), to differentiate a
26 26 # rev in the bundle and from a rev in the revlog, we check
27 27 # len(index[r]). If the tuple is bigger than 7, it is a bundle
28 28 # (it is bigger since we store the node to which the delta is)
29 29 #
30 30 revlog.revlog.__init__(self, opener, indexfile)
31 31 self.bundlefile = bundlefile
32 32 self.basemap = {}
33 33 def chunkpositer():
34 34 for chunk in changegroup.chunkiter(bundlefile):
35 35 pos = bundlefile.tell()
36 36 yield chunk, pos - len(chunk)
37 37 n = self.count()
38 38 prev = None
39 39 for chunk, start in chunkpositer():
40 40 size = len(chunk)
41 41 if size < 80:
42 42 raise util.Abort("invalid changegroup")
43 43 start += 80
44 44 size -= 80
45 45 node, p1, p2, cs = struct.unpack("20s20s20s20s", chunk[:80])
46 46 if node in self.nodemap:
47 47 prev = node
48 48 continue
49 49 for p in (p1, p2):
50 50 if not p in self.nodemap:
51 51 raise revlog.LookupError(hex(p1), _("unknown parent %s") % short(p1))
52 52 if linkmapper is None:
53 53 link = n
54 54 else:
55 55 link = linkmapper(cs)
56 56
57 57 if not prev:
58 58 prev = p1
59 59 # start, size, full unc. size, base (unused), link, p1, p2, node
60 60 e = (revlog.offset_type(start, 0), size, -1, -1, link,
61 61 self.rev(p1), self.rev(p2), node)
62 62 self.basemap[n] = prev
63 63 self.index.insert(-1, e)
64 64 self.nodemap[node] = n
65 65 prev = node
66 66 n += 1
67 67
68 68 def bundle(self, rev):
69 69 """is rev from the bundle"""
70 70 if rev < 0:
71 71 return False
72 72 return rev in self.basemap
73 73 def bundlebase(self, rev): return self.basemap[rev]
74 74 def chunk(self, rev, df=None, cachelen=4096):
75 75 # Warning: in case of bundle, the diff is against bundlebase,
76 76 # not against rev - 1
77 77 # XXX: could use some caching
78 78 if not self.bundle(rev):
79 79 return revlog.revlog.chunk(self, rev, df)
80 80 self.bundlefile.seek(self.start(rev))
81 81 return self.bundlefile.read(self.length(rev))
82 82
83 83 def revdiff(self, rev1, rev2):
84 84 """return or calculate a delta between two revisions"""
85 85 if self.bundle(rev1) and self.bundle(rev2):
86 86 # hot path for bundle
87 87 revb = self.rev(self.bundlebase(rev2))
88 88 if revb == rev1:
89 89 return self.chunk(rev2)
90 90 elif not self.bundle(rev1) and not self.bundle(rev2):
91 91 return revlog.revlog.revdiff(self, rev1, rev2)
92 92
93 93 return mdiff.textdiff(self.revision(self.node(rev1)),
94 94 self.revision(self.node(rev2)))
95 95
96 96 def revision(self, node):
97 97 """return an uncompressed revision of a given"""
98 98 if node == nullid: return ""
99 99
100 100 text = None
101 101 chain = []
102 102 iter_node = node
103 103 rev = self.rev(iter_node)
104 104 # reconstruct the revision if it is from a changegroup
105 105 while self.bundle(rev):
106 106 if self._cache and self._cache[0] == iter_node:
107 107 text = self._cache[2]
108 108 break
109 109 chain.append(rev)
110 110 iter_node = self.bundlebase(rev)
111 111 rev = self.rev(iter_node)
112 112 if text is None:
113 113 text = revlog.revlog.revision(self, iter_node)
114 114
115 115 while chain:
116 116 delta = self.chunk(chain.pop())
117 117 text = mdiff.patches(text, [delta])
118 118
119 119 p1, p2 = self.parents(node)
120 120 if node != revlog.hash(text, p1, p2):
121 121 raise revlog.RevlogError(_("integrity check failed on %s:%d")
122 122 % (self.datafile, self.rev(node)))
123 123
124 124 self._cache = (node, self.rev(node), text)
125 125 return text
126 126
127 127 def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
128 128 raise NotImplementedError
129 129 def addgroup(self, revs, linkmapper, transaction, unique=0):
130 130 raise NotImplementedError
131 131 def strip(self, rev, minlink):
132 132 raise NotImplementedError
133 133 def checksize(self):
134 134 raise NotImplementedError
135 135
136 136 class bundlechangelog(bundlerevlog, changelog.changelog):
137 137 def __init__(self, opener, bundlefile):
138 138 changelog.changelog.__init__(self, opener)
139 139 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile)
140 140
141 141 class bundlemanifest(bundlerevlog, manifest.manifest):
142 142 def __init__(self, opener, bundlefile, linkmapper):
143 143 manifest.manifest.__init__(self, opener)
144 144 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile,
145 145 linkmapper)
146 146
147 147 class bundlefilelog(bundlerevlog, filelog.filelog):
148 148 def __init__(self, opener, path, bundlefile, linkmapper):
149 149 filelog.filelog.__init__(self, opener, path)
150 150 bundlerevlog.__init__(self, opener, self.indexfile, bundlefile,
151 151 linkmapper)
152 152
153 153 class bundlerepository(localrepo.localrepository):
154 154 def __init__(self, ui, path, bundlename):
155 155 localrepo.localrepository.__init__(self, ui, path)
156 156
157 157 self._url = 'bundle:' + bundlename
158 158 if path: self._url += '+' + path
159 159
160 160 self.tempfile = None
161 161 self.bundlefile = open(bundlename, "rb")
162 162 header = self.bundlefile.read(6)
163 163 if not header.startswith("HG"):
164 164 raise util.Abort(_("%s: not a Mercurial bundle file") % bundlename)
165 165 elif not header.startswith("HG10"):
166 166 raise util.Abort(_("%s: unknown bundle version") % bundlename)
167 167 elif header == "HG10BZ":
168 168 fdtemp, temp = tempfile.mkstemp(prefix="hg-bundle-",
169 169 suffix=".hg10un", dir=self.path)
170 170 self.tempfile = temp
171 171 fptemp = os.fdopen(fdtemp, 'wb')
172 172 def generator(f):
173 173 zd = bz2.BZ2Decompressor()
174 174 zd.decompress("BZ")
175 175 for chunk in f:
176 176 yield zd.decompress(chunk)
177 177 gen = generator(util.filechunkiter(self.bundlefile, 4096))
178 178
179 179 try:
180 180 fptemp.write("HG10UN")
181 181 for chunk in gen:
182 182 fptemp.write(chunk)
183 183 finally:
184 184 fptemp.close()
185 185 self.bundlefile.close()
186 186
187 187 self.bundlefile = open(self.tempfile, "rb")
188 188 # seek right after the header
189 189 self.bundlefile.seek(6)
190 190 elif header == "HG10UN":
191 191 # nothing to do
192 192 pass
193 193 else:
194 194 raise util.Abort(_("%s: unknown bundle compression type")
195 195 % bundlename)
196 196 # dict with the mapping 'filename' -> position in the bundle
197 197 self.bundlefilespos = {}
198 198
199 199 def __getattr__(self, name):
200 200 if name == 'changelog':
201 201 self.changelog = bundlechangelog(self.sopener, self.bundlefile)
202 202 self.manstart = self.bundlefile.tell()
203 203 return self.changelog
204 204 if name == 'manifest':
205 205 self.bundlefile.seek(self.manstart)
206 206 self.manifest = bundlemanifest(self.sopener, self.bundlefile,
207 207 self.changelog.rev)
208 208 self.filestart = self.bundlefile.tell()
209 209 return self.manifest
210 210 if name == 'manstart':
211 211 self.changelog
212 212 return self.manstart
213 213 if name == 'filestart':
214 214 self.manifest
215 215 return self.filestart
216 216 return localrepo.localrepository.__getattr__(self, name)
217 217
218 218 def url(self):
219 219 return self._url
220 220
221 221 def dev(self):
222 222 return -1
223 223
224 224 def file(self, f):
225 225 if not self.bundlefilespos:
226 226 self.bundlefile.seek(self.filestart)
227 227 while 1:
228 228 chunk = changegroup.getchunk(self.bundlefile)
229 229 if not chunk:
230 230 break
231 231 self.bundlefilespos[chunk] = self.bundlefile.tell()
232 232 for c in changegroup.chunkiter(self.bundlefile):
233 233 pass
234 234
235 235 if f[0] == '/':
236 236 f = f[1:]
237 237 if f in self.bundlefilespos:
238 238 self.bundlefile.seek(self.bundlefilespos[f])
239 239 return bundlefilelog(self.sopener, f, self.bundlefile,
240 240 self.changelog.rev)
241 241 else:
242 242 return filelog.filelog(self.sopener, f)
243 243
244 244 def close(self):
245 245 """Close assigned bundle file immediately."""
246 246 self.bundlefile.close()
247 247
248 248 def __del__(self):
249 249 bundlefile = getattr(self, 'bundlefile', None)
250 250 if bundlefile and not bundlefile.closed:
251 251 bundlefile.close()
252 252 tempfile = getattr(self, 'tempfile', None)
253 253 if tempfile is not None:
254 254 os.unlink(tempfile)
255 255
256 256 def instance(ui, path, create):
257 257 if create:
258 258 raise util.Abort(_('cannot create new bundle repository'))
259 parentpath = ui.config("bundle", "mainreporoot", "")
260 if parentpath:
261 # Try to make the full path relative so we get a nice, short URL.
262 # In particular, we don't want temp dir names in test outputs.
263 cwd = os.getcwd()
264 if parentpath == cwd:
265 parentpath = ''
266 else:
267 cwd = os.path.join(cwd,'')
268 if parentpath.startswith(cwd):
269 parentpath = parentpath[len(cwd):]
259 270 path = util.drop_scheme('file', path)
260 271 if path.startswith('bundle:'):
261 272 path = util.drop_scheme('bundle', path)
262 273 s = path.split("+", 1)
263 274 if len(s) == 1:
264 repopath, bundlename = "", s[0]
275 repopath, bundlename = parentpath, s[0]
265 276 else:
266 277 repopath, bundlename = s
267 278 else:
268 repopath, bundlename = '', path
279 repopath, bundlename = parentpath, path
269 280 return bundlerepository(ui, repopath, bundlename)
@@ -1,403 +1,404 b''
1 1 # dispatch.py - command dispatching for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import *
9 9 from i18n import _
10 10 import os, sys, atexit, signal, pdb, traceback, socket, errno, shlex, time
11 11 import util, commands, hg, lock, fancyopts, revlog, version, extensions, hook
12 12 import cmdutil
13 13 import ui as _ui
14 14
15 15 class ParseError(Exception):
16 16 """Exception raised on errors in parsing the command line."""
17 17
18 18 def run():
19 19 "run the command in sys.argv"
20 20 sys.exit(dispatch(sys.argv[1:]))
21 21
22 22 def dispatch(args):
23 23 "run the command specified in args"
24 24 try:
25 25 u = _ui.ui(traceback='--traceback' in args)
26 26 except util.Abort, inst:
27 27 sys.stderr.write(_("abort: %s\n") % inst)
28 28 return -1
29 29 return _runcatch(u, args)
30 30
31 31 def _runcatch(ui, args):
32 32 def catchterm(*args):
33 33 raise util.SignalInterrupt
34 34
35 35 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
36 36 num = getattr(signal, name, None)
37 37 if num: signal.signal(num, catchterm)
38 38
39 39 try:
40 40 try:
41 41 # enter the debugger before command execution
42 42 if '--debugger' in args:
43 43 pdb.set_trace()
44 44 try:
45 45 return _dispatch(ui, args)
46 46 finally:
47 47 ui.flush()
48 48 except:
49 49 # enter the debugger when we hit an exception
50 50 if '--debugger' in args:
51 51 pdb.post_mortem(sys.exc_info()[2])
52 52 ui.print_exc()
53 53 raise
54 54
55 55 except ParseError, inst:
56 56 if inst.args[0]:
57 57 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
58 58 commands.help_(ui, inst.args[0])
59 59 else:
60 60 ui.warn(_("hg: %s\n") % inst.args[1])
61 61 commands.help_(ui, 'shortlist')
62 62 except cmdutil.AmbiguousCommand, inst:
63 63 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
64 64 (inst.args[0], " ".join(inst.args[1])))
65 65 except cmdutil.UnknownCommand, inst:
66 66 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
67 67 commands.help_(ui, 'shortlist')
68 68 except hg.RepoError, inst:
69 69 ui.warn(_("abort: %s!\n") % inst)
70 70 except lock.LockHeld, inst:
71 71 if inst.errno == errno.ETIMEDOUT:
72 72 reason = _('timed out waiting for lock held by %s') % inst.locker
73 73 else:
74 74 reason = _('lock held by %s') % inst.locker
75 75 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
76 76 except lock.LockUnavailable, inst:
77 77 ui.warn(_("abort: could not lock %s: %s\n") %
78 78 (inst.desc or inst.filename, inst.strerror))
79 79 except revlog.RevlogError, inst:
80 80 ui.warn(_("abort: %s!\n") % inst)
81 81 except util.SignalInterrupt:
82 82 ui.warn(_("killed!\n"))
83 83 except KeyboardInterrupt:
84 84 try:
85 85 ui.warn(_("interrupted!\n"))
86 86 except IOError, inst:
87 87 if inst.errno == errno.EPIPE:
88 88 if ui.debugflag:
89 89 ui.warn(_("\nbroken pipe\n"))
90 90 else:
91 91 raise
92 92 except socket.error, inst:
93 93 ui.warn(_("abort: %s\n") % inst[1])
94 94 except IOError, inst:
95 95 if hasattr(inst, "code"):
96 96 ui.warn(_("abort: %s\n") % inst)
97 97 elif hasattr(inst, "reason"):
98 98 try: # usually it is in the form (errno, strerror)
99 99 reason = inst.reason.args[1]
100 100 except: # it might be anything, for example a string
101 101 reason = inst.reason
102 102 ui.warn(_("abort: error: %s\n") % reason)
103 103 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
104 104 if ui.debugflag:
105 105 ui.warn(_("broken pipe\n"))
106 106 elif getattr(inst, "strerror", None):
107 107 if getattr(inst, "filename", None):
108 108 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
109 109 else:
110 110 ui.warn(_("abort: %s\n") % inst.strerror)
111 111 else:
112 112 raise
113 113 except OSError, inst:
114 114 if getattr(inst, "filename", None):
115 115 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
116 116 else:
117 117 ui.warn(_("abort: %s\n") % inst.strerror)
118 118 except util.UnexpectedOutput, inst:
119 119 ui.warn(_("abort: %s") % inst[0])
120 120 if not isinstance(inst[1], basestring):
121 121 ui.warn(" %r\n" % (inst[1],))
122 122 elif not inst[1]:
123 123 ui.warn(_(" empty string\n"))
124 124 else:
125 125 ui.warn("\n%r\n" % util.ellipsis(inst[1]))
126 126 except ImportError, inst:
127 127 m = str(inst).split()[-1]
128 128 ui.warn(_("abort: could not import module %s!\n") % m)
129 129 if m in "mpatch bdiff".split():
130 130 ui.warn(_("(did you forget to compile extensions?)\n"))
131 131 elif m in "zlib".split():
132 132 ui.warn(_("(is your Python install correct?)\n"))
133 133
134 134 except util.Abort, inst:
135 135 ui.warn(_("abort: %s\n") % inst)
136 136 except MemoryError:
137 137 ui.warn(_("abort: out of memory\n"))
138 138 except SystemExit, inst:
139 139 # Commands shouldn't sys.exit directly, but give a return code.
140 140 # Just in case catch this and and pass exit code to caller.
141 141 return inst.code
142 142 except:
143 143 ui.warn(_("** unknown exception encountered, details follow\n"))
144 144 ui.warn(_("** report bug details to "
145 145 "http://www.selenic.com/mercurial/bts\n"))
146 146 ui.warn(_("** or mercurial@selenic.com\n"))
147 147 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
148 148 % version.get_version())
149 149 raise
150 150
151 151 return -1
152 152
153 153 def _findrepo():
154 154 p = os.getcwd()
155 155 while not os.path.isdir(os.path.join(p, ".hg")):
156 156 oldp, p = p, os.path.dirname(p)
157 157 if p == oldp:
158 158 return None
159 159
160 160 return p
161 161
162 162 def _parse(ui, args):
163 163 options = {}
164 164 cmdoptions = {}
165 165
166 166 try:
167 167 args = fancyopts.fancyopts(args, commands.globalopts, options)
168 168 except fancyopts.getopt.GetoptError, inst:
169 169 raise ParseError(None, inst)
170 170
171 171 if args:
172 172 cmd, args = args[0], args[1:]
173 173 aliases, i = cmdutil.findcmd(ui, cmd, commands.table)
174 174 cmd = aliases[0]
175 175 defaults = ui.config("defaults", cmd)
176 176 if defaults:
177 177 args = shlex.split(defaults) + args
178 178 c = list(i[1])
179 179 else:
180 180 cmd = None
181 181 c = []
182 182
183 183 # combine global options into local
184 184 for o in commands.globalopts:
185 185 c.append((o[0], o[1], options[o[1]], o[3]))
186 186
187 187 try:
188 188 args = fancyopts.fancyopts(args, c, cmdoptions)
189 189 except fancyopts.getopt.GetoptError, inst:
190 190 raise ParseError(cmd, inst)
191 191
192 192 # separate global options back out
193 193 for o in commands.globalopts:
194 194 n = o[1]
195 195 options[n] = cmdoptions[n]
196 196 del cmdoptions[n]
197 197
198 198 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
199 199
200 200 def _parseconfig(config):
201 201 """parse the --config options from the command line"""
202 202 parsed = []
203 203 for cfg in config:
204 204 try:
205 205 name, value = cfg.split('=', 1)
206 206 section, name = name.split('.', 1)
207 207 if not section or not name:
208 208 raise IndexError
209 209 parsed.append((section, name, value))
210 210 except (IndexError, ValueError):
211 211 raise util.Abort(_('malformed --config option: %s') % cfg)
212 212 return parsed
213 213
214 214 def _earlygetopt(aliases, args):
215 215 """Return list of values for an option (or aliases).
216 216
217 217 The values are listed in the order they appear in args.
218 218 The options and values are removed from args.
219 219 """
220 220 try:
221 221 argcount = args.index("--")
222 222 except ValueError:
223 223 argcount = len(args)
224 224 shortopts = [opt for opt in aliases if len(opt) == 2]
225 225 values = []
226 226 pos = 0
227 227 while pos < argcount:
228 228 if args[pos] in aliases:
229 229 if pos + 1 >= argcount:
230 230 # ignore and let getopt report an error if there is no value
231 231 break
232 232 del args[pos]
233 233 values.append(args.pop(pos))
234 234 argcount -= 2
235 235 elif args[pos][:2] in shortopts:
236 236 # short option can have no following space, e.g. hg log -Rfoo
237 237 values.append(args.pop(pos)[2:])
238 238 argcount -= 1
239 239 else:
240 240 pos += 1
241 241 return values
242 242
243 243 _loaded = {}
244 244 def _dispatch(ui, args):
245 245 # read --config before doing anything else
246 246 # (e.g. to change trust settings for reading .hg/hgrc)
247 247 config = _earlygetopt(['--config'], args)
248 248 if config:
249 249 ui.updateopts(config=_parseconfig(config))
250 250
251 251 # check for cwd
252 252 cwd = _earlygetopt(['--cwd'], args)
253 253 if cwd:
254 254 os.chdir(cwd[-1])
255 255
256 256 # read the local repository .hgrc into a local ui object
257 257 path = _findrepo() or ""
258 258 if not path:
259 259 lui = ui
260 260 if path:
261 261 try:
262 262 lui = _ui.ui(parentui=ui)
263 263 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
264 264 except IOError:
265 265 pass
266 266
267 267 # now we can expand paths, even ones in .hg/hgrc
268 268 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
269 269 if rpath:
270 270 path = lui.expandpath(rpath[-1])
271 271 lui = _ui.ui(parentui=ui)
272 272 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
273 273
274 274 extensions.loadall(lui)
275 275 for name, module in extensions.extensions():
276 276 if name in _loaded:
277 277 continue
278 278 cmdtable = getattr(module, 'cmdtable', {})
279 279 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
280 280 if overrides:
281 281 ui.warn(_("extension '%s' overrides commands: %s\n")
282 282 % (name, " ".join(overrides)))
283 283 commands.table.update(cmdtable)
284 284 _loaded[name] = 1
285 285 # check for fallback encoding
286 286 fallback = lui.config('ui', 'fallbackencoding')
287 287 if fallback:
288 288 util._fallbackencoding = fallback
289 289
290 290 fullargs = args
291 291 cmd, func, args, options, cmdoptions = _parse(lui, args)
292 292
293 293 if options["config"]:
294 294 raise util.Abort(_("Option --config may not be abbreviated!"))
295 295 if options["cwd"]:
296 296 raise util.Abort(_("Option --cwd may not be abbreviated!"))
297 297 if options["repository"]:
298 298 raise util.Abort(_(
299 299 "Option -R has to be separated from other options (i.e. not -qR) "
300 300 "and --repository may only be abbreviated as --repo!"))
301 301
302 302 if options["encoding"]:
303 303 util._encoding = options["encoding"]
304 304 if options["encodingmode"]:
305 305 util._encodingmode = options["encodingmode"]
306 306 if options["time"]:
307 307 def get_times():
308 308 t = os.times()
309 309 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
310 310 t = (t[0], t[1], t[2], t[3], time.clock())
311 311 return t
312 312 s = get_times()
313 313 def print_time():
314 314 t = get_times()
315 315 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
316 316 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
317 317 atexit.register(print_time)
318 318
319 319 ui.updateopts(options["verbose"], options["debug"], options["quiet"],
320 320 not options["noninteractive"], options["traceback"])
321 321
322 322 if options['help']:
323 323 return commands.help_(ui, cmd, options['version'])
324 324 elif options['version']:
325 325 return commands.version_(ui)
326 326 elif not cmd:
327 327 return commands.help_(ui, 'shortlist')
328 328
329 329 repo = None
330 330 if cmd not in commands.norepo.split():
331 331 try:
332 332 repo = hg.repository(ui, path=path)
333 333 ui = repo.ui
334 ui.setconfig("bundle", "mainreporoot", repo.root)
334 335 if not repo.local():
335 336 raise util.Abort(_("repository '%s' is not local") % path)
336 337 except hg.RepoError:
337 338 if cmd not in commands.optionalrepo.split():
338 339 if not path:
339 340 raise hg.RepoError(_("There is no Mercurial repository here"
340 341 " (.hg not found)"))
341 342 raise
342 343 d = lambda: func(ui, repo, *args, **cmdoptions)
343 344 else:
344 345 d = lambda: func(ui, *args, **cmdoptions)
345 346
346 347 # run pre-hook, and abort if it fails
347 348 ret = hook.hook(ui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs))
348 349 if ret:
349 350 return ret
350 351 ret = _runcommand(ui, options, cmd, d)
351 352 # run post-hook, passing command result
352 353 hook.hook(ui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
353 354 result = ret)
354 355 return ret
355 356
356 357 def _runcommand(ui, options, cmd, cmdfunc):
357 358 def checkargs():
358 359 try:
359 360 return cmdfunc()
360 361 except TypeError, inst:
361 362 # was this an argument error?
362 363 tb = traceback.extract_tb(sys.exc_info()[2])
363 364 if len(tb) != 2: # no
364 365 raise
365 366 raise ParseError(cmd, _("invalid arguments"))
366 367
367 368 if options['profile']:
368 369 import hotshot, hotshot.stats
369 370 prof = hotshot.Profile("hg.prof")
370 371 try:
371 372 try:
372 373 return prof.runcall(checkargs)
373 374 except:
374 375 try:
375 376 ui.warn(_('exception raised - generating '
376 377 'profile anyway\n'))
377 378 except:
378 379 pass
379 380 raise
380 381 finally:
381 382 prof.close()
382 383 stats = hotshot.stats.load("hg.prof")
383 384 stats.strip_dirs()
384 385 stats.sort_stats('time', 'calls')
385 386 stats.print_stats(40)
386 387 elif options['lsprof']:
387 388 try:
388 389 from mercurial import lsprof
389 390 except ImportError:
390 391 raise util.Abort(_(
391 392 'lsprof not available - install from '
392 393 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
393 394 p = lsprof.Profiler()
394 395 p.enable(subcalls=True)
395 396 try:
396 397 return checkargs()
397 398 finally:
398 399 p.disable()
399 400 stats = lsprof.Stats(p.getstats())
400 401 stats.sort()
401 402 stats.pprint(top=10, file=sys.stderr, climit=5)
402 403 else:
403 404 return checkargs()
@@ -1,108 +1,117 b''
1 1 #!/bin/sh
2 2
3 3 cp "$TESTDIR"/printenv.py .
4 4
5 5 echo "====== Setting up test"
6 6 hg init test
7 7 cd test
8 8 echo 0 > afile
9 9 hg add afile
10 10 hg commit -m "0.0" -d "1000000 0"
11 11 echo 1 >> afile
12 12 hg commit -m "0.1" -d "1000000 0"
13 13 echo 2 >> afile
14 14 hg commit -m "0.2" -d "1000000 0"
15 15 echo 3 >> afile
16 16 hg commit -m "0.3" -d "1000000 0"
17 17 hg update -C 0
18 18 echo 1 >> afile
19 19 hg commit -m "1.1" -d "1000000 0"
20 20 echo 2 >> afile
21 21 hg commit -m "1.2" -d "1000000 0"
22 22 echo "a line" > fred
23 23 echo 3 >> afile
24 24 hg add fred
25 25 hg commit -m "1.3" -d "1000000 0"
26 26 hg mv afile adifferentfile
27 27 hg commit -m "1.3m" -d "1000000 0"
28 28 hg update -C 3
29 29 hg mv afile anotherfile
30 30 hg commit -m "0.3m" -d "1000000 0"
31 31 hg verify
32 32 cd ..
33 33 hg init empty
34 34
35 35 echo "====== Bundle test to full.hg"
36 36 hg -R test bundle full.hg empty
37 37 echo "====== Unbundle full.hg in test"
38 38 hg -R test unbundle full.hg
39 39 echo "====== Verify empty"
40 40 hg -R empty heads
41 41 hg -R empty verify
42 42
43 43 echo "====== Pull full.hg into test (using --cwd)"
44 44 hg --cwd test pull ../full.hg
45 45 echo "====== Pull full.hg into empty (using --cwd)"
46 46 hg --cwd empty pull ../full.hg
47 47 echo "====== Rollback empty"
48 48 hg -R empty rollback
49 49 echo "====== Pull full.hg into empty again (using --cwd)"
50 50 hg --cwd empty pull ../full.hg
51 51
52 echo "====== Pull full.hg into test (using -R)"
53 hg -R test pull full.hg
54 echo "====== Pull full.hg into empty (using -R)"
55 hg -R empty pull full.hg
56 echo "====== Rollback empty"
57 hg -R empty rollback
58 echo "====== Pull full.hg into empty again (using -R)"
59 hg -R empty pull full.hg
60
52 61 echo "====== Log -R full.hg in fresh empty"
53 62 rm -r empty
54 63 hg init empty
55 64 cd empty
56 65 hg -R bundle://../full.hg log
57 66
58 67 echo "====== Pull ../full.hg into empty (with hook)"
59 68 echo '[hooks]' >> .hg/hgrc
60 69 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
61 70 #doesn't work (yet ?)
62 71 #hg -R bundle://../full.hg verify
63 72 hg pull bundle://../full.hg
64 73 cd ..
65 74
66 75 echo "====== Create partial clones"
67 76 rm -r empty
68 77 hg init empty
69 78 hg clone -r 3 test partial
70 79 hg clone partial partial2
71 80 cd partial
72 81 echo "====== Log -R full.hg in partial"
73 82 hg -R bundle://../full.hg log
74 83 echo "====== Incoming full.hg in partial"
75 84 hg incoming bundle://../full.hg
76 85 echo "====== Outgoing -R full.hg vs partial2 in partial"
77 86 hg -R bundle://../full.hg outgoing ../partial2
78 87 echo "====== Outgoing -R does-not-exist.hg vs partial2 in partial"
79 88 hg -R bundle://../does-not-exist.hg outgoing ../partial2
80 89 cd ..
81 90
82 91 # test for http://www.selenic.com/mercurial/bts/issue216
83 92 echo "====== Unbundle incremental bundles into fresh empty in one go"
84 93 rm -r empty
85 94 hg init empty
86 95 hg -R test bundle --base null -r 0 ../0.hg
87 96 hg -R test bundle --base 0 -r 1 ../1.hg
88 97 hg -R empty unbundle -u ../0.hg ../1.hg
89 98
90 99 # test for 540d1059c802
91 100 echo "====== test for 540d1059c802"
92 101 hg init orig
93 102 cd orig
94 103 echo foo > foo
95 104 hg add foo
96 105 hg ci -m 'add foo' -d '0 0'
97 106
98 107 hg clone . ../copy
99 108 hg tag -d '0 0' foo
100 109
101 110 cd ../copy
102 111 echo >> foo
103 112 hg ci -m 'change foo' -d '0 0'
104 113 hg bundle ../bundle.hg ../orig
105 114
106 115 cd ../orig
107 116 hg incoming ../bundle.hg
108 117 cd ..
@@ -1,250 +1,268 b''
1 1 ====== Setting up test
2 2 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 3 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
4 4 checking changesets
5 5 checking manifests
6 6 crosschecking files in changesets and manifests
7 7 checking files
8 8 4 files, 9 changesets, 7 total revisions
9 9 ====== Bundle test to full.hg
10 10 searching for changes
11 11 ====== Unbundle full.hg in test
12 12 adding changesets
13 13 adding manifests
14 14 adding file changes
15 15 added 0 changesets with 0 changes to 4 files
16 16 (run 'hg update' to get a working copy)
17 17 ====== Verify empty
18 18 changeset: -1:000000000000
19 19 tag: tip
20 20 user:
21 21 date: Thu Jan 01 00:00:00 1970 +0000
22 22
23 23 checking changesets
24 24 checking manifests
25 25 crosschecking files in changesets and manifests
26 26 checking files
27 27 0 files, 0 changesets, 0 total revisions
28 28 ====== Pull full.hg into test (using --cwd)
29 29 pulling from ../full.hg
30 30 searching for changes
31 31 no changes found
32 32 ====== Pull full.hg into empty (using --cwd)
33 33 pulling from ../full.hg
34 34 requesting all changes
35 35 adding changesets
36 36 adding manifests
37 37 adding file changes
38 38 added 9 changesets with 7 changes to 4 files (+1 heads)
39 39 (run 'hg heads' to see heads, 'hg merge' to merge)
40 40 ====== Rollback empty
41 41 rolling back last transaction
42 42 ====== Pull full.hg into empty again (using --cwd)
43 43 pulling from ../full.hg
44 44 requesting all changes
45 45 adding changesets
46 46 adding manifests
47 47 adding file changes
48 48 added 9 changesets with 7 changes to 4 files (+1 heads)
49 49 (run 'hg heads' to see heads, 'hg merge' to merge)
50 ====== Pull full.hg into test (using -R)
51 pulling from full.hg
52 searching for changes
53 no changes found
54 ====== Pull full.hg into empty (using -R)
55 pulling from full.hg
56 searching for changes
57 no changes found
58 ====== Rollback empty
59 rolling back last transaction
60 ====== Pull full.hg into empty again (using -R)
61 pulling from full.hg
62 requesting all changes
63 adding changesets
64 adding manifests
65 adding file changes
66 added 9 changesets with 7 changes to 4 files (+1 heads)
67 (run 'hg heads' to see heads, 'hg merge' to merge)
50 68 ====== Log -R full.hg in fresh empty
51 69 changeset: 8:836ac62537ab
52 70 tag: tip
53 71 parent: 3:ac69c658229d
54 72 user: test
55 73 date: Mon Jan 12 13:46:40 1970 +0000
56 74 summary: 0.3m
57 75
58 76 changeset: 7:80fe151401c2
59 77 user: test
60 78 date: Mon Jan 12 13:46:40 1970 +0000
61 79 summary: 1.3m
62 80
63 81 changeset: 6:1e3f6b843bd6
64 82 user: test
65 83 date: Mon Jan 12 13:46:40 1970 +0000
66 84 summary: 1.3
67 85
68 86 changeset: 5:024e4e7df376
69 87 user: test
70 88 date: Mon Jan 12 13:46:40 1970 +0000
71 89 summary: 1.2
72 90
73 91 changeset: 4:5f4f3ceb285e
74 92 parent: 0:5649c9d34dd8
75 93 user: test
76 94 date: Mon Jan 12 13:46:40 1970 +0000
77 95 summary: 1.1
78 96
79 97 changeset: 3:ac69c658229d
80 98 user: test
81 99 date: Mon Jan 12 13:46:40 1970 +0000
82 100 summary: 0.3
83 101
84 102 changeset: 2:d62976ca1e50
85 103 user: test
86 104 date: Mon Jan 12 13:46:40 1970 +0000
87 105 summary: 0.2
88 106
89 107 changeset: 1:10b2180f755b
90 108 user: test
91 109 date: Mon Jan 12 13:46:40 1970 +0000
92 110 summary: 0.1
93 111
94 112 changeset: 0:5649c9d34dd8
95 113 user: test
96 114 date: Mon Jan 12 13:46:40 1970 +0000
97 115 summary: 0.0
98 116
99 117 ====== Pull ../full.hg into empty (with hook)
100 118 changegroup hook: HG_NODE=5649c9d34dd87d0ecb5fd39672128376e83b22e1 HG_SOURCE=pull HG_URL=bundle:../full.hg
101 119 pulling from bundle://../full.hg
102 120 requesting all changes
103 121 adding changesets
104 122 adding manifests
105 123 adding file changes
106 124 added 9 changesets with 7 changes to 4 files (+1 heads)
107 125 (run 'hg heads' to see heads, 'hg merge' to merge)
108 126 ====== Create partial clones
109 127 requesting all changes
110 128 adding changesets
111 129 adding manifests
112 130 adding file changes
113 131 added 4 changesets with 4 changes to 1 files
114 132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
115 133 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 134 ====== Log -R full.hg in partial
117 135 changeset: 8:836ac62537ab
118 136 tag: tip
119 137 parent: 3:ac69c658229d
120 138 user: test
121 139 date: Mon Jan 12 13:46:40 1970 +0000
122 140 summary: 0.3m
123 141
124 142 changeset: 7:80fe151401c2
125 143 user: test
126 144 date: Mon Jan 12 13:46:40 1970 +0000
127 145 summary: 1.3m
128 146
129 147 changeset: 6:1e3f6b843bd6
130 148 user: test
131 149 date: Mon Jan 12 13:46:40 1970 +0000
132 150 summary: 1.3
133 151
134 152 changeset: 5:024e4e7df376
135 153 user: test
136 154 date: Mon Jan 12 13:46:40 1970 +0000
137 155 summary: 1.2
138 156
139 157 changeset: 4:5f4f3ceb285e
140 158 parent: 0:5649c9d34dd8
141 159 user: test
142 160 date: Mon Jan 12 13:46:40 1970 +0000
143 161 summary: 1.1
144 162
145 163 changeset: 3:ac69c658229d
146 164 user: test
147 165 date: Mon Jan 12 13:46:40 1970 +0000
148 166 summary: 0.3
149 167
150 168 changeset: 2:d62976ca1e50
151 169 user: test
152 170 date: Mon Jan 12 13:46:40 1970 +0000
153 171 summary: 0.2
154 172
155 173 changeset: 1:10b2180f755b
156 174 user: test
157 175 date: Mon Jan 12 13:46:40 1970 +0000
158 176 summary: 0.1
159 177
160 178 changeset: 0:5649c9d34dd8
161 179 user: test
162 180 date: Mon Jan 12 13:46:40 1970 +0000
163 181 summary: 0.0
164 182
165 183 ====== Incoming full.hg in partial
166 184 comparing with bundle://../full.hg
167 185 searching for changes
168 186 changeset: 4:5f4f3ceb285e
169 187 parent: 0:5649c9d34dd8
170 188 user: test
171 189 date: Mon Jan 12 13:46:40 1970 +0000
172 190 summary: 1.1
173 191
174 192 changeset: 5:024e4e7df376
175 193 user: test
176 194 date: Mon Jan 12 13:46:40 1970 +0000
177 195 summary: 1.2
178 196
179 197 changeset: 6:1e3f6b843bd6
180 198 user: test
181 199 date: Mon Jan 12 13:46:40 1970 +0000
182 200 summary: 1.3
183 201
184 202 changeset: 7:80fe151401c2
185 203 user: test
186 204 date: Mon Jan 12 13:46:40 1970 +0000
187 205 summary: 1.3m
188 206
189 207 changeset: 8:836ac62537ab
190 208 tag: tip
191 209 parent: 3:ac69c658229d
192 210 user: test
193 211 date: Mon Jan 12 13:46:40 1970 +0000
194 212 summary: 0.3m
195 213
196 214 ====== Outgoing -R full.hg vs partial2 in partial
197 215 comparing with ../partial2
198 216 searching for changes
199 217 changeset: 4:5f4f3ceb285e
200 218 parent: 0:5649c9d34dd8
201 219 user: test
202 220 date: Mon Jan 12 13:46:40 1970 +0000
203 221 summary: 1.1
204 222
205 223 changeset: 5:024e4e7df376
206 224 user: test
207 225 date: Mon Jan 12 13:46:40 1970 +0000
208 226 summary: 1.2
209 227
210 228 changeset: 6:1e3f6b843bd6
211 229 user: test
212 230 date: Mon Jan 12 13:46:40 1970 +0000
213 231 summary: 1.3
214 232
215 233 changeset: 7:80fe151401c2
216 234 user: test
217 235 date: Mon Jan 12 13:46:40 1970 +0000
218 236 summary: 1.3m
219 237
220 238 changeset: 8:836ac62537ab
221 239 tag: tip
222 240 parent: 3:ac69c658229d
223 241 user: test
224 242 date: Mon Jan 12 13:46:40 1970 +0000
225 243 summary: 0.3m
226 244
227 245 ====== Outgoing -R does-not-exist.hg vs partial2 in partial
228 246 abort: No such file or directory: ../does-not-exist.hg
229 247 ====== Unbundle incremental bundles into fresh empty in one go
230 248 adding changesets
231 249 adding manifests
232 250 adding file changes
233 251 added 1 changesets with 1 changes to 1 files
234 252 adding changesets
235 253 adding manifests
236 254 adding file changes
237 255 added 1 changesets with 1 changes to 1 files
238 256 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 257 ====== test for 540d1059c802
240 258 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
241 259 searching for changes
242 260 comparing with ../bundle.hg
243 261 searching for changes
244 262 changeset: 2:ed1b79f46b9a
245 263 tag: tip
246 264 parent: 0:bbd179dfa0a7
247 265 user: test
248 266 date: Thu Jan 01 00:00:00 1970 +0000
249 267 summary: change foo
250 268
General Comments 0
You need to be logged in to leave comments. Login now