Show More
@@ -0,0 +1,39 | |||||
|
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 | |||||
|
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 class queue: | |||||
471 | patcherr = not patcherr |
|
471 | patcherr = not patcherr | |
472 |
|
472 | |||
473 | if merge and files: |
|
473 | if merge and files: | |
474 | # Mark as merged and update dirstate parent info |
|
474 | # Mark as removed/merged and update dirstate parent info | |
475 | repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm') |
|
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 | p1, p2 = repo.dirstate.parents() |
|
484 | p1, p2 = repo.dirstate.parents() | |
477 | repo.dirstate.setparents(p1, merge) |
|
485 | repo.dirstate.setparents(p1, merge) | |
478 | files = patch.updatedir(self.ui, repo, files, wlock=wlock) |
|
486 | files = patch.updatedir(self.ui, repo, files, wlock=wlock) |
@@ -314,7 +314,7 class dirstate(object): | |||||
314 | def write(self): |
|
314 | def write(self): | |
315 | if not self.dirty: |
|
315 | if not self.dirty: | |
316 | return |
|
316 | return | |
317 | st = self.opener("dirstate", "w", atomic=True) |
|
317 | st = self.opener("dirstate", "w", atomictemp=True) | |
318 | st.write("".join(self.pl)) |
|
318 | st.write("".join(self.pl)) | |
319 | for f, e in self.map.items(): |
|
319 | for f, e in self.map.items(): | |
320 | c = self.copied(f) |
|
320 | c = self.copied(f) | |
@@ -322,6 +322,7 class dirstate(object): | |||||
322 | f = f + "\0" + c |
|
322 | f = f + "\0" + c | |
323 | e = struct.pack(self.format, e[0], e[1], e[2], e[3], len(f)) |
|
323 | e = struct.pack(self.format, e[0], e[1], e[2], e[3], len(f)) | |
324 | st.write(e + f) |
|
324 | st.write(e + f) | |
|
325 | st.rename() | |||
325 | self.dirty = 0 |
|
326 | self.dirty = 0 | |
326 |
|
327 | |||
327 | def filterfiles(self, files): |
|
328 | def filterfiles(self, files): |
@@ -417,10 +417,11 class localrepository(repo.repository): | |||||
417 |
|
417 | |||
418 | def _writebranchcache(self, branches, tip, tiprev): |
|
418 | def _writebranchcache(self, branches, tip, tiprev): | |
419 | try: |
|
419 | try: | |
420 | f = self.opener("branch.cache", "w") |
|
420 | f = self.opener("branch.cache", "w", atomictemp=True) | |
421 | f.write("%s %s\n" % (hex(tip), tiprev)) |
|
421 | f.write("%s %s\n" % (hex(tip), tiprev)) | |
422 | for label, node in branches.iteritems(): |
|
422 | for label, node in branches.iteritems(): | |
423 | f.write("%s %s\n" % (hex(node), label)) |
|
423 | f.write("%s %s\n" % (hex(node), label)) | |
|
424 | f.rename() | |||
424 | except IOError: |
|
425 | except IOError: | |
425 | pass |
|
426 | pass | |
426 |
|
427 |
@@ -27,7 +27,7 class templater(object): | |||||
27 | is treated as name of template file. |
|
27 | is treated as name of template file. | |
28 |
|
28 | |||
29 | templater is asked to expand a key in map. it looks up key, and |
|
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 | foo in map, and substituting it. expansion is recursive: it stops |
|
31 | foo in map, and substituting it. expansion is recursive: it stops | |
32 | when there is no more {foo} to replace. |
|
32 | when there is no more {foo} to replace. | |
33 |
|
33 |
@@ -766,6 +766,9 def checkfolding(path): | |||||
766 | except: |
|
766 | except: | |
767 | return True |
|
767 | return True | |
768 |
|
768 | |||
|
769 | _umask = os.umask(0) | |||
|
770 | os.umask(_umask) | |||
|
771 | ||||
769 | def checkexec(path): |
|
772 | def checkexec(path): | |
770 | """ |
|
773 | """ | |
771 | Check whether the given path is on a filesystem with UNIX-like exec flags |
|
774 | Check whether the given path is on a filesystem with UNIX-like exec flags | |
@@ -1103,18 +1106,32 def opener(base, audit=True): | |||||
1103 | p = base |
|
1106 | p = base | |
1104 | audit_p = audit |
|
1107 | audit_p = audit | |
1105 |
|
1108 | |||
1106 | def mktempcopy(name): |
|
1109 | def mktempcopy(name, emptyok=False): | |
1107 | d, fn = os.path.split(name) |
|
1110 | d, fn = os.path.split(name) | |
1108 | fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d) |
|
1111 | fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d) | |
1109 | os.close(fd) |
|
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 | try: |
|
1125 | try: | |
1112 | try: |
|
1126 | try: | |
1113 | ifp = posixfile(name, "rb") |
|
1127 | ifp = posixfile(name, "rb") | |
1114 | except IOError, inst: |
|
1128 | except IOError, inst: | |
|
1129 | if inst.errno == errno.ENOENT: | |||
|
1130 | return temp | |||
1115 | if not getattr(inst, 'filename', None): |
|
1131 | if not getattr(inst, 'filename', None): | |
1116 | inst.filename = name |
|
1132 | inst.filename = name | |
1117 | raise |
|
1133 | raise | |
|
1134 | ofp = posixfile(temp, "wb") | |||
1118 | for chunk in filechunkiter(ifp): |
|
1135 | for chunk in filechunkiter(ifp): | |
1119 | ofp.write(chunk) |
|
1136 | ofp.write(chunk) | |
1120 | ifp.close() |
|
1137 | ifp.close() | |
@@ -1123,15 +1140,13 def opener(base, audit=True): | |||||
1123 | try: os.unlink(temp) |
|
1140 | try: os.unlink(temp) | |
1124 | except: pass |
|
1141 | except: pass | |
1125 | raise |
|
1142 | raise | |
1126 | st = os.lstat(name) |
|
|||
1127 | os.chmod(temp, st.st_mode) |
|
|||
1128 | return temp |
|
1143 | return temp | |
1129 |
|
1144 | |||
1130 | class atomictempfile(posixfile): |
|
1145 | class atomictempfile(posixfile): | |
1131 | """the file will only be copied when rename is called""" |
|
1146 | """the file will only be copied when rename is called""" | |
1132 | def __init__(self, name, mode): |
|
1147 | def __init__(self, name, mode): | |
1133 | self.__name = name |
|
1148 | self.__name = name | |
1134 | self.temp = mktempcopy(name) |
|
1149 | self.temp = mktempcopy(name, emptyok=('w' in mode)) | |
1135 | posixfile.__init__(self, self.temp, mode) |
|
1150 | posixfile.__init__(self, self.temp, mode) | |
1136 | def rename(self): |
|
1151 | def rename(self): | |
1137 | if not self.closed: |
|
1152 | if not self.closed: | |
@@ -1165,10 +1180,10 def opener(base, audit=True): | |||||
1165 | try: |
|
1180 | try: | |
1166 | nlink = nlinks(f) |
|
1181 | nlink = nlinks(f) | |
1167 | except OSError: |
|
1182 | except OSError: | |
|
1183 | nlink = 0 | |||
1168 | d = os.path.dirname(f) |
|
1184 | d = os.path.dirname(f) | |
1169 | if not os.path.isdir(d): |
|
1185 | if not os.path.isdir(d): | |
1170 | os.makedirs(d) |
|
1186 | os.makedirs(d) | |
1171 | else: |
|
|||
1172 |
|
|
1187 | if atomic: | |
1173 |
|
|
1188 | return atomicfile(f, mode) | |
1174 |
|
|
1189 | elif atomictemp: |
General Comments 0
You need to be logged in to leave comments.
Login now