Show More
@@ -0,0 +1,39 b'' | |||
|
1 | #!/bin/sh | |
|
2 | ||
|
3 | # Test issue 529 - mq aborts when merging patch deleting files | |
|
4 | ||
|
5 | rewrite_path() | |
|
6 | { | |
|
7 | sed -e 's:\\:/:g' -e 's:[^ ]*/t/::g' | |
|
8 | } | |
|
9 | ||
|
10 | echo "[extensions]" >> $HGRCPATH | |
|
11 | echo "hgext.mq=" >> $HGRCPATH | |
|
12 | ||
|
13 | # Commit two dummy files in "init" changeset | |
|
14 | hg init t | |
|
15 | cd t | |
|
16 | echo a > a | |
|
17 | echo b > b | |
|
18 | hg ci -Am init | |
|
19 | hg tag -l init | |
|
20 | ||
|
21 | # Create a patch removing a | |
|
22 | hg qnew rm_a | |
|
23 | hg rm a | |
|
24 | hg qrefresh -m "rm a" | |
|
25 | ||
|
26 | # Save the patch queue so we can merge it later | |
|
27 | hg qsave -c -e 2>&1 | rewrite_path | |
|
28 | ||
|
29 | # Update b and commit in an "update" changeset | |
|
30 | hg up -C init | |
|
31 | echo b >> b | |
|
32 | hg st | |
|
33 | hg ci -m update | |
|
34 | ||
|
35 | # Here, qpush used to abort with : | |
|
36 | # The system cannot find the file specified => a | |
|
37 | hg manifest | |
|
38 | hg qpush -a -m 2>&1 | rewrite_path | |
|
39 | hg manifest |
@@ -0,0 +1,11 b'' | |||
|
1 | adding a | |
|
2 | adding b | |
|
3 | copy .hg/patches to .hg/patches.1 | |
|
4 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
|
5 | M b | |
|
6 | a | |
|
7 | b | |
|
8 | merging with queue at: .hg/patches.1 | |
|
9 | applying rm_a | |
|
10 | Now at: rm_a | |
|
11 | b |
@@ -471,8 +471,16 b' class queue:' | |||
|
471 | 471 | patcherr = not patcherr |
|
472 | 472 | |
|
473 | 473 | if merge and files: |
|
474 | # Mark as merged and update dirstate parent info | |
|
475 | repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm') | |
|
474 | # Mark as removed/merged and update dirstate parent info | |
|
475 | removed = [] | |
|
476 | merged = [] | |
|
477 | for f in files: | |
|
478 | if os.path.exists(repo.dirstate.wjoin(f)): | |
|
479 | merged.append(f) | |
|
480 | else: | |
|
481 | removed.append(f) | |
|
482 | repo.dirstate.update(repo.dirstate.filterfiles(removed), 'r') | |
|
483 | repo.dirstate.update(repo.dirstate.filterfiles(merged), 'm') | |
|
476 | 484 | p1, p2 = repo.dirstate.parents() |
|
477 | 485 | repo.dirstate.setparents(p1, merge) |
|
478 | 486 | files = patch.updatedir(self.ui, repo, files, wlock=wlock) |
@@ -314,7 +314,7 b' class dirstate(object):' | |||
|
314 | 314 | def write(self): |
|
315 | 315 | if not self.dirty: |
|
316 | 316 | return |
|
317 | st = self.opener("dirstate", "w", atomic=True) | |
|
317 | st = self.opener("dirstate", "w", atomictemp=True) | |
|
318 | 318 | st.write("".join(self.pl)) |
|
319 | 319 | for f, e in self.map.items(): |
|
320 | 320 | c = self.copied(f) |
@@ -322,6 +322,7 b' class dirstate(object):' | |||
|
322 | 322 | f = f + "\0" + c |
|
323 | 323 | e = struct.pack(self.format, e[0], e[1], e[2], e[3], len(f)) |
|
324 | 324 | st.write(e + f) |
|
325 | st.rename() | |
|
325 | 326 | self.dirty = 0 |
|
326 | 327 | |
|
327 | 328 | def filterfiles(self, files): |
@@ -417,10 +417,11 b' class localrepository(repo.repository):' | |||
|
417 | 417 | |
|
418 | 418 | def _writebranchcache(self, branches, tip, tiprev): |
|
419 | 419 | try: |
|
420 | f = self.opener("branch.cache", "w") | |
|
420 | f = self.opener("branch.cache", "w", atomictemp=True) | |
|
421 | 421 | f.write("%s %s\n" % (hex(tip), tiprev)) |
|
422 | 422 | for label, node in branches.iteritems(): |
|
423 | 423 | f.write("%s %s\n" % (hex(node), label)) |
|
424 | f.rename() | |
|
424 | 425 | except IOError: |
|
425 | 426 | pass |
|
426 | 427 |
@@ -27,7 +27,7 b' class templater(object):' | |||
|
27 | 27 | is treated as name of template file. |
|
28 | 28 | |
|
29 | 29 | templater is asked to expand a key in map. it looks up key, and |
|
30 |
looks for |
|
|
30 | looks for strings like this: {foo}. it expands {foo} by looking up | |
|
31 | 31 | foo in map, and substituting it. expansion is recursive: it stops |
|
32 | 32 | when there is no more {foo} to replace. |
|
33 | 33 |
@@ -766,6 +766,9 b' def checkfolding(path):' | |||
|
766 | 766 | except: |
|
767 | 767 | return True |
|
768 | 768 | |
|
769 | _umask = os.umask(0) | |
|
770 | os.umask(_umask) | |
|
771 | ||
|
769 | 772 | def checkexec(path): |
|
770 | 773 | """ |
|
771 | 774 | Check whether the given path is on a filesystem with UNIX-like exec flags |
@@ -1103,18 +1106,32 b' def opener(base, audit=True):' | |||
|
1103 | 1106 | p = base |
|
1104 | 1107 | audit_p = audit |
|
1105 | 1108 | |
|
1106 | def mktempcopy(name): | |
|
1109 | def mktempcopy(name, emptyok=False): | |
|
1107 | 1110 | d, fn = os.path.split(name) |
|
1108 | 1111 | fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d) |
|
1109 | 1112 | os.close(fd) |
|
1110 | ofp = posixfile(temp, "wb") | |
|
1113 | # Temporary files are created with mode 0600, which is usually not | |
|
1114 | # what we want. If the original file already exists, just copy | |
|
1115 | # its mode. Otherwise, manually obey umask. | |
|
1116 | try: | |
|
1117 | st_mode = os.lstat(name).st_mode | |
|
1118 | except OSError, inst: | |
|
1119 | if inst.errno != errno.ENOENT: | |
|
1120 | raise | |
|
1121 | st_mode = 0666 & ~_umask | |
|
1122 | os.chmod(temp, st_mode) | |
|
1123 | if emptyok: | |
|
1124 | return temp | |
|
1111 | 1125 | try: |
|
1112 | 1126 | try: |
|
1113 | 1127 | ifp = posixfile(name, "rb") |
|
1114 | 1128 | except IOError, inst: |
|
1129 | if inst.errno == errno.ENOENT: | |
|
1130 | return temp | |
|
1115 | 1131 | if not getattr(inst, 'filename', None): |
|
1116 | 1132 | inst.filename = name |
|
1117 | 1133 | raise |
|
1134 | ofp = posixfile(temp, "wb") | |
|
1118 | 1135 | for chunk in filechunkiter(ifp): |
|
1119 | 1136 | ofp.write(chunk) |
|
1120 | 1137 | ifp.close() |
@@ -1123,15 +1140,13 b' def opener(base, audit=True):' | |||
|
1123 | 1140 | try: os.unlink(temp) |
|
1124 | 1141 | except: pass |
|
1125 | 1142 | raise |
|
1126 | st = os.lstat(name) | |
|
1127 | os.chmod(temp, st.st_mode) | |
|
1128 | 1143 | return temp |
|
1129 | 1144 | |
|
1130 | 1145 | class atomictempfile(posixfile): |
|
1131 | 1146 | """the file will only be copied when rename is called""" |
|
1132 | 1147 | def __init__(self, name, mode): |
|
1133 | 1148 | self.__name = name |
|
1134 | self.temp = mktempcopy(name) | |
|
1149 | self.temp = mktempcopy(name, emptyok=('w' in mode)) | |
|
1135 | 1150 | posixfile.__init__(self, self.temp, mode) |
|
1136 | 1151 | def rename(self): |
|
1137 | 1152 | if not self.closed: |
@@ -1165,16 +1180,16 b' def opener(base, audit=True):' | |||
|
1165 | 1180 | try: |
|
1166 | 1181 | nlink = nlinks(f) |
|
1167 | 1182 | except OSError: |
|
1183 | nlink = 0 | |
|
1168 | 1184 | d = os.path.dirname(f) |
|
1169 | 1185 | if not os.path.isdir(d): |
|
1170 | 1186 | os.makedirs(d) |
|
1171 |
|
|
|
1172 |
|
|
|
1173 | return atomicfile(f, mode) | |
|
1174 |
|
|
|
1175 | return atomictempfile(f, mode) | |
|
1176 | if nlink > 1: | |
|
1177 | rename(mktempcopy(f), f) | |
|
1187 | if atomic: | |
|
1188 | return atomicfile(f, mode) | |
|
1189 | elif atomictemp: | |
|
1190 | return atomictempfile(f, mode) | |
|
1191 | if nlink > 1: | |
|
1192 | rename(mktempcopy(f), f) | |
|
1178 | 1193 | return posixfile(f, mode) |
|
1179 | 1194 | |
|
1180 | 1195 | return o |
General Comments 0
You need to be logged in to leave comments.
Login now