/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: 2019-06-03 23:48:08 UTC
  • mfrom: (7316 work)
  • mto: This revision was merged to the branch mainline in revision 7328.
  • Revision ID: jelmer@jelmer.uk-20190603234808-15yk5c7054tj8e2b
Merge trunk.

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
16
17
 
17
18
from __future__ import absolute_import
18
19
 
 
20
"""Diff and patch functionality"""
 
21
 
19
22
import errno
20
23
import os
21
24
from subprocess import Popen, PIPE
 
25
import sys
22
26
 
23
 
from .errors import NoDiff3
 
27
from .errors import NoDiff3, BzrError
24
28
from .textfile import check_text_path
25
29
 
26
 
"""Diff and patch functionality"""
27
 
 
28
 
__docformat__ = "restructuredtext"
 
30
class PatchFailed(BzrError):
 
31
 
 
32
    _fmt = """Patch application failed"""
 
33
 
 
34
 
 
35
class PatchInvokeError(BzrError):
 
36
 
 
37
    _fmt = """Error invoking patch: %(errstr)s%(stderr)s"""
 
38
    internal_error = False
 
39
 
 
40
    def __init__(self, e, stderr=''):
 
41
        self.exception = e
 
42
        self.errstr = os.strerror(e.errno)
 
43
        self.stderr = '\n' + stderr
29
44
 
30
45
 
31
46
_do_close_fds = True
96
111
            raise
97
112
    if status not in (0, 1):
98
113
        raise Exception(stderr)
99
 
    f = open(out_file, 'wb')
100
 
    try:
 
114
    with open(out_file, 'wb') as f:
101
115
        f.write(output)
102
 
    finally:
103
 
        f.close()
104
116
    return status
 
117
 
 
118
 
 
119
def patch_tree(tree, patches, strip=0, reverse=False, dry_run=False,
 
120
               quiet=False, out=None):
 
121
    """Apply a patch to a tree.
 
122
 
 
123
    Args:
 
124
      tree: A MutableTree object
 
125
      patches: list of patches as bytes
 
126
      strip: Strip X segments of paths
 
127
      reverse: Apply reversal of patch
 
128
      dry_run: Dry run
 
129
    """
 
130
    return run_patch(tree.basedir, patches, strip, reverse, dry_run,
 
131
                     quiet, out=out)
 
132
 
 
133
 
 
134
def run_patch(directory, patches, strip=0, reverse=False, dry_run=False,
 
135
              quiet=False, _patch_cmd='patch', target_file=None, out=None):
 
136
    args = [_patch_cmd, '-d', directory, '-s', '-p%d' % strip, '-f']
 
137
    if quiet:
 
138
        args.append('--quiet')
 
139
 
 
140
    if sys.platform == "win32":
 
141
        args.append('--binary')
 
142
 
 
143
    if reverse:
 
144
        args.append('-R')
 
145
    if dry_run:
 
146
        if sys.platform.startswith('freebsd'):
 
147
            args.append('--check')
 
148
        else:
 
149
            args.append('--dry-run')
 
150
        stderr = PIPE
 
151
    else:
 
152
        stderr = None
 
153
    if target_file is not None:
 
154
        args.append(target_file)
 
155
 
 
156
    try:
 
157
        process = Popen(args, stdin=PIPE, stdout=PIPE, stderr=stderr)
 
158
    except OSError as e:
 
159
        raise PatchInvokeError(e)
 
160
    try:
 
161
        for patch in patches:
 
162
            process.stdin.write(bytes(patch))
 
163
        process.stdin.close()
 
164
 
 
165
    except IOError as e:
 
166
        raise PatchInvokeError(e, process.stderr.read())
 
167
 
 
168
    result = process.wait()
 
169
    if not dry_run:
 
170
        if out is not None:
 
171
            out.write(process.stdout.read())
 
172
        else:
 
173
            process.stdout.read()
 
174
    if result != 0:
 
175
        raise PatchFailed()
 
176
 
 
177
    return result