--- a/hgext/keyword.py Wed May 18 23:48:13 2011 +0200
+++ b/hgext/keyword.py Wed May 18 23:48:13 2011 +0200
@@ -595,11 +595,11 @@
wlock.release()
# monkeypatches
- def kwpatchfile_init(orig, self, ui, fname, backend,
+ def kwpatchfile_init(orig, self, ui, fname, backend, mode,
missing=False, eolmode=None):
'''Monkeypatch/wrap patch.patchfile.__init__ to avoid
rejects or conflicts due to expanded keywords in working dir.'''
- orig(self, ui, fname, backend, missing, eolmode)
+ orig(self, ui, fname, backend, mode, missing, eolmode)
# shrink keywords read from working dir
self.lines = kwt.shrinklines(self.fname, self.lines)
--- a/mercurial/patch.py Wed May 18 23:48:13 2011 +0200
+++ b/mercurial/patch.py Wed May 18 23:48:13 2011 +0200
@@ -372,8 +372,10 @@
"""
raise NotImplementedError
- def writelines(self, fname, lines):
- """Write lines to target file."""
+ def writelines(self, fname, lines, mode):
+ """Write lines to target file. mode is a (islink, isexec)
+ tuple, or None if there is no mode information.
+ """
raise NotImplementedError
def unlink(self, fname):
@@ -397,6 +399,10 @@
def exists(self, fname):
raise NotImplementedError
+ def setmode(self, fname, islink, isexec):
+ """Change target file mode."""
+ raise NotImplementedError
+
class fsbackend(abstractbackend):
def __init__(self, ui, basedir):
super(fsbackend, self).__init__(ui)
@@ -414,29 +420,24 @@
finally:
fp.close()
- def writelines(self, fname, lines):
- # Ensure supplied data ends in fname, being a regular file or
- # a symlink. _updatedir will -too magically- take care
- # of setting it to the proper type afterwards.
- st_mode = None
- islink = os.path.islink(self._join(fname))
- if islink:
- fp = cStringIO.StringIO()
- else:
+ def writelines(self, fname, lines, mode):
+ if not mode:
+ # Preserve mode information
+ isexec, islink = False, False
try:
- st_mode = os.lstat(self._join(fname)).st_mode & 0777
+ isexec = os.lstat(self._join(fname)).st_mode & 0100 != 0
+ islink = os.path.islink(self._join(fname))
except OSError, e:
if e.errno != errno.ENOENT:
raise
- fp = self.opener(fname, 'w')
- try:
- fp.writelines(lines)
- if islink:
- self.opener.symlink(fp.getvalue(), fname)
- if st_mode is not None:
- os.chmod(self._join(fname), st_mode)
- finally:
- fp.close()
+ else:
+ islink, isexec = mode
+ if islink:
+ self.opener.symlink(''.join(lines), fname)
+ else:
+ self.opener(fname, 'w').writelines(lines)
+ if isexec:
+ util.setflags(self._join(fname), False, True)
def unlink(self, fname):
os.unlink(self._join(fname))
@@ -470,13 +471,17 @@
def exists(self, fname):
return os.path.lexists(self._join(fname))
+ def setmode(self, fname, islink, isexec):
+ util.setflags(self._join(fname), islink, isexec)
+
# @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
eolmodes = ['strict', 'crlf', 'lf', 'auto']
class patchfile(object):
- def __init__(self, ui, fname, backend, missing=False, eolmode='strict'):
+ def __init__(self, ui, fname, backend, mode, missing=False,
+ eolmode='strict'):
self.fname = fname
self.eolmode = eolmode
self.eol = None
@@ -485,6 +490,7 @@
self.lines = []
self.exists = False
self.missing = missing
+ self.mode = mode
if not missing:
try:
self.lines = self.backend.readlines(fname)
@@ -516,7 +522,7 @@
self.printfile(False)
self.hunks = 0
- def writelines(self, fname, lines):
+ def writelines(self, fname, lines, mode):
if self.eolmode == 'auto':
eol = self.eol
elif self.eolmode == 'crlf':
@@ -532,7 +538,7 @@
rawlines.append(l)
lines = rawlines
- self.backend.writelines(fname, lines)
+ self.backend.writelines(fname, lines, mode)
def printfile(self, warn):
if self.fileprinted:
@@ -670,7 +676,7 @@
def close(self):
if self.dirty:
- self.writelines(self.fname, self.lines)
+ self.writelines(self.fname, self.lines, self.mode)
self.write_rej()
return len(self.rej)
@@ -1087,14 +1093,16 @@
hunknum += 1
if emitfile:
emitfile = False
- yield 'file', (afile, bfile, h)
+ yield 'file', (afile, bfile, h, gpatch and gpatch.mode or None)
yield 'hunk', h
elif state == BFILE and x.startswith('GIT binary patch'):
- h = binhunk(changed[bfile])
+ gpatch = changed[bfile]
+ h = binhunk(gpatch)
hunknum += 1
if emitfile:
emitfile = False
- yield 'file', ('a/' + afile, 'b/' + bfile, h)
+ yield 'file', ('a/' + afile, 'b/' + bfile, h,
+ gpatch and gpatch.mode or None)
h.extract(lr)
yield 'hunk', h
elif x.startswith('diff --git'):
@@ -1181,11 +1189,11 @@
elif state == 'file':
if current_file:
rejects += current_file.close()
- afile, bfile, first_hunk = values
+ afile, bfile, first_hunk, mode = values
try:
current_file, missing = selectfile(backend, afile, bfile,
first_hunk, strip)
- current_file = patcher(ui, current_file, backend,
+ current_file = patcher(ui, current_file, backend, mode,
missing=missing, eolmode=eolmode)
except PatchError, inst:
ui.warn(str(inst) + '\n')
@@ -1208,6 +1216,16 @@
if current_file:
rejects += current_file.close()
+ # Handle mode changes without hunk
+ for gp in changed.itervalues():
+ if not gp or not gp.mode:
+ continue
+ if gp.op == 'ADD' and not backend.exists(gp.path):
+ # Added files without content have no hunk and must be created
+ backend.writelines(gp.path, [], gp.mode)
+ else:
+ backend.setmode(gp.path, gp.mode[0], gp.mode[1])
+
if rejects:
return -1
return err
@@ -1240,16 +1258,6 @@
if (not similarity) and removes:
wctx.remove(sorted(removes), True)
- for f in patches:
- gp = patches[f]
- if gp and gp.mode:
- islink, isexec = gp.mode
- dst = repo.wjoin(gp.path)
- # patch won't create empty files
- if gp.op == 'ADD' and not os.path.lexists(dst):
- flags = (isexec and 'x' or '') + (islink and 'l' or '')
- repo.wwrite(gp.path, '', flags)
- util.setflags(dst, islink, isexec)
scmutil.addremove(repo, cfiles, similarity=similarity)
files = patches.keys()
files.extend([r for r in removes if r not in files])
@@ -1359,7 +1367,7 @@
if state == 'hunk':
continue
elif state == 'file':
- afile, bfile, first_hunk = values
+ afile, bfile, first_hunk, mode = values
current_file, missing = selectfile(backend, afile, bfile,
first_hunk, strip)
changed.add(current_file)