/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/patch.py

  • Committer: Jelmer Vernooij
  • Date: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
2
# Copyright (C) 2005, 2008 Aaron Bentley, 2006 Michael Ellerman
2
3
#
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
14
15
# along with this program; if not, write to the Free Software
15
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
 
 
18
from __future__ import absolute_import
 
19
 
 
20
"""Diff and patch functionality"""
17
21
 
18
22
import errno
19
23
import os
20
24
from subprocess import Popen, PIPE
21
 
 
22
 
from bzrlib.errors import NoDiff3
23
 
from bzrlib.textfile import check_text_path
24
 
 
25
 
"""Diff and patch functionality"""
26
 
 
27
 
__docformat__ = "restructuredtext"
 
25
import sys
 
26
import tempfile
 
27
 
 
28
from .errors import NoDiff3, BzrError
 
29
from .textfile import check_text_path
 
30
 
 
31
class PatchFailed(BzrError):
 
32
 
 
33
    _fmt = """Patch application failed"""
 
34
 
 
35
 
 
36
class PatchInvokeError(BzrError):
 
37
 
 
38
    _fmt = """Error invoking patch: %(errstr)s%(stderr)s"""
 
39
    internal_error = False
 
40
 
 
41
    def __init__(self, e, stderr=''):
 
42
        self.exception = e
 
43
        self.errstr = os.strerror(e.errno)
 
44
        self.stderr = '\n' + stderr
28
45
 
29
46
 
30
47
_do_close_fds = True
46
63
    stdout, stderr = process.communicate(input)
47
64
    status = process.wait()
48
65
    if status < 0:
49
 
        raise Exception("%s killed by signal %i" (args[0], -status))
 
66
        raise Exception("%s killed by signal %i" % (args[0], -status))
50
67
    return stdout, stderr, status
51
68
 
52
69
 
88
105
    args.extend((mine_path, older_path, yours_path))
89
106
    try:
90
107
        output, stderr, status = write_to_cmd(args)
91
 
    except OSError, e:
 
108
    except OSError as e:
92
109
        if e.errno == errno.ENOENT:
93
110
            raise NoDiff3
94
111
        else:
95
112
            raise
96
113
    if status not in (0, 1):
97
114
        raise Exception(stderr)
98
 
    f = open(out_file, 'wb')
99
 
    try:
 
115
    with open(out_file, 'wb') as f:
100
116
        f.write(output)
101
 
    finally:
102
 
        f.close()
103
117
    return status
 
118
 
 
119
 
 
120
def patch_tree(tree, patches, strip=0, reverse=False, dry_run=False,
 
121
               quiet=False, out=None):
 
122
    """Apply a patch to a tree.
 
123
 
 
124
    Args:
 
125
      tree: A MutableTree object
 
126
      patches: list of patches as bytes
 
127
      strip: Strip X segments of paths
 
128
      reverse: Apply reversal of patch
 
129
      dry_run: Dry run
 
130
    """
 
131
    return run_patch(tree.basedir, patches, strip, reverse, dry_run,
 
132
                     quiet, out=out)
 
133
 
 
134
 
 
135
def run_patch(directory, patches, strip=0, reverse=False, dry_run=False,
 
136
              quiet=False, _patch_cmd='patch', target_file=None, out=None):
 
137
    args = [_patch_cmd, '-d', directory, '-s', '-p%d' % strip, '-f']
 
138
    if quiet:
 
139
        args.append('--quiet')
 
140
 
 
141
    if sys.platform == "win32":
 
142
        args.append('--binary')
 
143
 
 
144
    if reverse:
 
145
        args.append('-R')
 
146
    if dry_run:
 
147
        if sys.platform.startswith('freebsd'):
 
148
            args.append('--check')
 
149
        else:
 
150
            args.append('--dry-run')
 
151
        stderr = PIPE
 
152
    else:
 
153
        stderr = None
 
154
    if target_file is not None:
 
155
        args.append(target_file)
 
156
 
 
157
    try:
 
158
        process = Popen(args, stdin=PIPE, stdout=PIPE, stderr=stderr)
 
159
    except OSError as e:
 
160
        raise PatchInvokeError(e)
 
161
    try:
 
162
        for patch in patches:
 
163
            process.stdin.write(bytes(patch))
 
164
        process.stdin.close()
 
165
 
 
166
    except IOError as e:
 
167
        raise PatchInvokeError(e, process.stderr.read())
 
168
 
 
169
    result = process.wait()
 
170
    if not dry_run:
 
171
        if out is not None:
 
172
            out.write(process.stdout.read())
 
173
        else:
 
174
            process.stdout.read()
 
175
    if result != 0:
 
176
        raise PatchFailed()
 
177
 
 
178
    return result
 
179
 
 
180
 
 
181
def iter_patched_from_hunks(orig_lines, hunks):
 
182
    """Iterate through a series of lines with a patch applied.
 
183
    This handles a single file, and does exact, not fuzzy patching.
 
184
 
 
185
    :param orig_lines: The unpatched lines.
 
186
    :param hunks: An iterable of Hunk instances.
 
187
 
 
188
    This is different from breezy.patches in that it invokes the patch
 
189
    command.
 
190
    """
 
191
    with tempfile.NamedTemporaryFile() as f:
 
192
        f.writelines(orig_lines)
 
193
        f.flush()
 
194
        # TODO(jelmer): Stream patch contents to command, rather than
 
195
        # serializing the entire patch upfront.
 
196
        serialized = b''.join([hunk.as_bytes() for hunk in hunks])
 
197
        args = ["patch", "-f", "-s", "--posix", "--binary",
 
198
                "-o", "-", f.name, "-r", "-"]
 
199
        stdout, stderr, status = write_to_cmd(args, serialized)
 
200
    if status == 0:
 
201
        return [stdout]
 
202
    raise PatchFailed(stderr)