/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: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

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
 
17
 
from __future__ import absolute_import
 
18
"""Diff and patch functionality"""
18
19
 
19
20
import errno
20
21
import os
21
22
from subprocess import Popen, PIPE
 
23
import sys
 
24
import tempfile
22
25
 
23
 
from .errors import NoDiff3
 
26
from .errors import NoDiff3, BzrError
24
27
from .textfile import check_text_path
25
28
 
26
 
"""Diff and patch functionality"""
27
 
 
28
 
__docformat__ = "restructuredtext"
 
29
class PatchFailed(BzrError):
 
30
 
 
31
    _fmt = """Patch application failed"""
 
32
 
 
33
 
 
34
class PatchInvokeError(BzrError):
 
35
 
 
36
    _fmt = """Error invoking patch: %(errstr)s%(stderr)s"""
 
37
    internal_error = False
 
38
 
 
39
    def __init__(self, e, stderr=''):
 
40
        self.exception = e
 
41
        self.errstr = os.strerror(e.errno)
 
42
        self.stderr = '\n' + stderr
29
43
 
30
44
 
31
45
_do_close_fds = True
47
61
    stdout, stderr = process.communicate(input)
48
62
    status = process.wait()
49
63
    if status < 0:
50
 
        raise Exception("%s killed by signal %i" (args[0], -status))
 
64
        raise Exception("%s killed by signal %i" % (args[0], -status))
51
65
    return stdout, stderr, status
52
66
 
53
67
 
96
110
            raise
97
111
    if status not in (0, 1):
98
112
        raise Exception(stderr)
99
 
    f = open(out_file, 'wb')
100
 
    try:
 
113
    with open(out_file, 'wb') as f:
101
114
        f.write(output)
102
 
    finally:
103
 
        f.close()
104
115
    return status
 
116
 
 
117
 
 
118
def patch_tree(tree, patches, strip=0, reverse=False, dry_run=False,
 
119
               quiet=False, out=None):
 
120
    """Apply a patch to a tree.
 
121
 
 
122
    Args:
 
123
      tree: A MutableTree object
 
124
      patches: list of patches as bytes
 
125
      strip: Strip X segments of paths
 
126
      reverse: Apply reversal of patch
 
127
      dry_run: Dry run
 
128
    """
 
129
    return run_patch(tree.basedir, patches, strip, reverse, dry_run,
 
130
                     quiet, out=out)
 
131
 
 
132
 
 
133
def run_patch(directory, patches, strip=0, reverse=False, dry_run=False,
 
134
              quiet=False, _patch_cmd='patch', target_file=None, out=None):
 
135
    args = [_patch_cmd, '-d', directory, '-s', '-p%d' % strip, '-f']
 
136
    if quiet:
 
137
        args.append('--quiet')
 
138
 
 
139
    if sys.platform == "win32":
 
140
        args.append('--binary')
 
141
 
 
142
    if reverse:
 
143
        args.append('-R')
 
144
    if dry_run:
 
145
        if sys.platform.startswith('freebsd'):
 
146
            args.append('--check')
 
147
        else:
 
148
            args.append('--dry-run')
 
149
        stderr = PIPE
 
150
    else:
 
151
        stderr = None
 
152
    if target_file is not None:
 
153
        args.append(target_file)
 
154
 
 
155
    try:
 
156
        process = Popen(args, stdin=PIPE, stdout=PIPE, stderr=stderr)
 
157
    except OSError as e:
 
158
        raise PatchInvokeError(e)
 
159
    try:
 
160
        for patch in patches:
 
161
            process.stdin.write(bytes(patch))
 
162
        process.stdin.close()
 
163
 
 
164
    except IOError as e:
 
165
        raise PatchInvokeError(e, process.stderr.read())
 
166
 
 
167
    result = process.wait()
 
168
    if not dry_run:
 
169
        if out is not None:
 
170
            out.write(process.stdout.read())
 
171
        else:
 
172
            process.stdout.read()
 
173
    if result != 0:
 
174
        raise PatchFailed()
 
175
 
 
176
    return result
 
177
 
 
178
 
 
179
def iter_patched_from_hunks(orig_lines, hunks):
 
180
    """Iterate through a series of lines with a patch applied.
 
181
    This handles a single file, and does exact, not fuzzy patching.
 
182
 
 
183
    :param orig_lines: The unpatched lines.
 
184
    :param hunks: An iterable of Hunk instances.
 
185
 
 
186
    This is different from breezy.patches in that it invokes the patch
 
187
    command.
 
188
    """
 
189
    with tempfile.NamedTemporaryFile() as f:
 
190
        f.writelines(orig_lines)
 
191
        f.flush()
 
192
        # TODO(jelmer): Stream patch contents to command, rather than
 
193
        # serializing the entire patch upfront.
 
194
        serialized = b''.join([hunk.as_bytes() for hunk in hunks])
 
195
        args = ["patch", "-f", "-s", "--posix", "--binary",
 
196
                "-o", "-", f.name, "-r", "-"]
 
197
        stdout, stderr, status = write_to_cmd(args, serialized)
 
198
    if status == 0:
 
199
        return [stdout]
 
200
    raise PatchFailed(stderr)