~ubuntu-branches/ubuntu/precise/mercurial/precise-updates

« back to all changes in this revision

Viewing changes to mercurial/patch.py

  • Committer: Bazaar Package Importer
  • Author(s): Javi Merino
  • Date: 2011-03-06 16:01:58 UTC
  • mto: (28.1.2 sid) (1.1.14)
  • mto: This revision was merged to the branch mainline in revision 32.
  • Revision ID: james.westby@ubuntu.com-20110306160158-y94pzpmtd7b1xgjk
Tags: upstream-1.8
ImportĀ upstreamĀ versionĀ 1.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
# This software may be used and distributed according to the terms of the
7
7
# GNU General Public License version 2 or any later version.
8
8
 
9
 
import cStringIO, email.Parser, os, re
 
9
import cStringIO, email.Parser, os, errno, re
10
10
import tempfile, zlib
11
11
 
12
12
from i18n import _
429
429
        # Ensure supplied data ends in fname, being a regular file or
430
430
        # a symlink. cmdutil.updatedir will -too magically- take care
431
431
        # of setting it to the proper type afterwards.
 
432
        st_mode = None
432
433
        islink = os.path.islink(fname)
433
434
        if islink:
434
435
            fp = cStringIO.StringIO()
435
436
        else:
 
437
            try:
 
438
                st_mode = os.lstat(fname).st_mode & 0777
 
439
            except OSError, e:
 
440
                if e.errno != errno.ENOENT:
 
441
                    raise
436
442
            fp = self.opener(fname, 'w')
437
443
        try:
438
444
            if self.eolmode == 'auto':
451
457
                fp.writelines(lines)
452
458
            if islink:
453
459
                self.opener.symlink(fp.getvalue(), fname)
 
460
            if st_mode is not None:
 
461
                os.chmod(fname, st_mode)
454
462
        finally:
455
463
            fp.close()
456
464
 
976
984
    fp.seek(pos)
977
985
    return gitpatches
978
986
 
979
 
def iterhunks(ui, fp, sourcefile=None):
 
987
def iterhunks(ui, fp):
980
988
    """Read a patch and yield the following events:
981
989
    - ("file", afile, bfile, firsthunk): select a new target file.
982
990
    - ("hunk", hunk): a new hunk is ready to be applied, follows a
997
1005
    BFILE = 1
998
1006
    context = None
999
1007
    lr = linereader(fp)
1000
 
    # gitworkdone is True if a git operation (copy, rename, ...) was
1001
 
    # performed already for the current file. Useful when the file
1002
 
    # section may have no hunk.
1003
 
    gitworkdone = False
1004
1008
 
1005
1009
    while True:
1006
1010
        newfile = newgitfile = False
1012
1016
                current_hunk.fix_newline()
1013
1017
            yield 'hunk', current_hunk
1014
1018
            current_hunk = None
1015
 
        if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or
 
1019
        if (state == BFILE and ((not context and x[0] == '@') or
1016
1020
            ((context is not False) and x.startswith('***************')))):
1017
1021
            if context is None and x.startswith('***************'):
1018
1022
                context = True
1034
1038
        elif x.startswith('diff --git'):
1035
1039
            # check for git diff, scanning the whole patch file if needed
1036
1040
            m = gitre.match(x)
1037
 
            gitworkdone = False
1038
1041
            if m:
1039
1042
                afile, bfile = m.group(1, 2)
1040
1043
                if not git:
1049
1052
                if gp and (gp.op in ('COPY', 'DELETE', 'RENAME', 'ADD')
1050
1053
                           or gp.mode):
1051
1054
                    afile = bfile
1052
 
                    gitworkdone = True
1053
1055
                newgitfile = True
1054
1056
        elif x.startswith('---'):
1055
1057
            # check for a unified diff
1077
1079
            afile = parsefilename(x)
1078
1080
            bfile = parsefilename(l2)
1079
1081
 
1080
 
        if newfile:
1081
 
            gitworkdone = False
1082
 
 
1083
1082
        if newgitfile or newfile:
1084
1083
            emitfile = True
1085
1084
            state = BFILE
1091
1090
            raise PatchError(_("malformed patch %s %s") % (afile,
1092
1091
                             current_hunk.desc))
1093
1092
 
1094
 
def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'):
 
1093
def applydiff(ui, fp, changed, strip=1, eolmode='strict'):
1095
1094
    """Reads a patch from fp and tries to apply it.
1096
1095
 
1097
1096
    The dict 'changed' is filled in with all of the filenames changed
1105
1104
    Callers probably want to call 'cmdutil.updatedir' after this to
1106
1105
    apply certain categories of changes not done by this function.
1107
1106
    """
1108
 
    return _applydiff(
1109
 
        ui, fp, patchfile, copyfile,
1110
 
        changed, strip=strip, sourcefile=sourcefile, eolmode=eolmode)
1111
 
 
1112
 
 
1113
 
def _applydiff(ui, fp, patcher, copyfn, changed, strip=1,
1114
 
               sourcefile=None, eolmode='strict'):
 
1107
    return _applydiff(ui, fp, patchfile, copyfile, changed, strip=strip,
 
1108
                      eolmode=eolmode)
 
1109
 
 
1110
def _applydiff(ui, fp, patcher, copyfn, changed, strip=1, eolmode='strict'):
1115
1111
    rejects = 0
1116
1112
    err = 0
1117
1113
    current_file = None
1126
1122
        current_file.write_rej()
1127
1123
        return len(current_file.rej)
1128
1124
 
1129
 
    for state, values in iterhunks(ui, fp, sourcefile):
 
1125
    for state, values in iterhunks(ui, fp):
1130
1126
        if state == 'hunk':
1131
1127
            if not current_file:
1132
1128
                continue
1139
1135
            rejects += closefile()
1140
1136
            afile, bfile, first_hunk = values
1141
1137
            try:
1142
 
                if sourcefile:
1143
 
                    current_file = patcher(ui, sourcefile, opener,
1144
 
                                           eolmode=eolmode)
1145
 
                else:
1146
 
                    current_file, missing = selectfile(afile, bfile,
1147
 
                                                       first_hunk, strip)
1148
 
                    current_file = patcher(ui, current_file, opener,
1149
 
                                           missing=missing, eolmode=eolmode)
 
1138
                current_file, missing = selectfile(afile, bfile,
 
1139
                                                   first_hunk, strip)
 
1140
                current_file = patcher(ui, current_file, opener,
 
1141
                                       missing=missing, eolmode=eolmode)
1150
1142
            except PatchError, err:
1151
1143
                ui.warn(str(err) + '\n')
1152
1144
                current_file = None
1537
1529
                yield text
1538
1530
 
1539
1531
def diffstatdata(lines):
 
1532
    diffre = re.compile('^diff .*-r [a-z0-9]+\s(.*)$')
 
1533
 
1540
1534
    filename, adds, removes = None, 0, 0
1541
1535
    for line in lines:
1542
1536
        if line.startswith('diff'):
1547
1541
            adds, removes = 0, 0
1548
1542
            if line.startswith('diff --git'):
1549
1543
                filename = gitre.search(line).group(1)
1550
 
            else:
 
1544
            elif line.startswith('diff -r'):
1551
1545
                # format: "diff -r ... -r ... filename"
1552
 
                filename = line.split(None, 5)[-1]
 
1546
                filename = diffre.search(line).group(1)
1553
1547
        elif line.startswith('+') and not line.startswith('+++'):
1554
1548
            adds += 1
1555
1549
        elif line.startswith('-') and not line.startswith('---'):