~bzr-pqm/bzr/bzr.dev

1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
16
17
1534.7.130 by Aaron Bentley
More conflict handling, test porting
18
import errno
493 by Martin Pool
- Merge aaron's merge command
19
import os
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
20
from subprocess import Popen, PIPE
1534.7.130 by Aaron Bentley
More conflict handling, test porting
21
22
from bzrlib.errors import NoDiff3
1558.15.3 by Aaron Bentley
Handle binary files for diff3 merges
23
from bzrlib.textfile import check_text_path
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
24
25
"""Diff and patch functionality"""
26
493 by Martin Pool
- Merge aaron's merge command
27
__docformat__ = "restructuredtext"
28
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
29
30
_do_close_fds = True
31
if os.name == 'nt':
32
    _do_close_fds = False
33
34
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
35
def write_to_cmd(args, input=""):
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
36
    """Spawn a process, and wait for the result
37
38
    If the process is killed, an exception is raised
39
40
    :param args: The command line, the first entry should be the program name
41
    :param input: [optional] The text to send the process on stdin
42
    :return: (stdout, stderr, status)
43
    """
44
    process = Popen(args, bufsize=len(input), stdin=PIPE, stdout=PIPE,
45
                    stderr=PIPE, close_fds=_do_close_fds)
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
46
    stdout, stderr = process.communicate(input)
47
    status = process.wait()
48
    if status < 0:
49
        raise Exception("%s killed by signal %i" (args[0], -status))
50
    return stdout, stderr, status
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
51
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
52
493 by Martin Pool
- Merge aaron's merge command
53
def patch(patch_contents, filename, output_filename=None, reverse=False):
54
    """Apply a patch to a file, to produce another output file.  This is should
55
    be suitable for our limited purposes.
56
57
    :param patch_contents: The contents of the patch to apply
58
    :type patch_contents: str
59
    :param filename: the name of the file to apply the patch to
60
    :type filename: str
61
    :param output_filename: The filename to produce.  If None, file is \
62
    modified in-place
63
    :type output_filename: str or NoneType
64
    :param reverse: If true, apply the patch in reverse
65
    :type reverse: bool
66
    :return: 0 on success, 1 if some hunks failed
67
    """
68
    args = ["patch", "-f", "-s", "--posix", "--binary"]
69
    if reverse:
70
        args.append("--reverse")
71
    if output_filename is not None:
72
        args.extend(("-o", output_filename))
73
    args.append(filename)
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
74
    stdout, stderr, status = write_to_cmd(args, patch_contents)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
75
    return status
493 by Martin Pool
- Merge aaron's merge command
76
77
78
def diff3(out_file, mine_path, older_path, yours_path):
79
    def add_label(args, label):
80
        args.extend(("-L", label))
1558.15.3 by Aaron Bentley
Handle binary files for diff3 merges
81
    check_text_path(mine_path)
82
    check_text_path(older_path)
83
    check_text_path(yours_path)
493 by Martin Pool
- Merge aaron's merge command
84
    args = ['diff3', "-E", "--merge"]
85
    add_label(args, "TREE")
86
    add_label(args, "ANCESTOR")
87
    add_label(args, "MERGE-SOURCE")
88
    args.extend((mine_path, older_path, yours_path))
1534.7.130 by Aaron Bentley
More conflict handling, test porting
89
    try:
90
        output, stderr, status = write_to_cmd(args)
91
    except OSError, e:
92
        if e.errno == errno.ENOENT:
93
            raise NoDiff3
94
        else:
95
            raise
493 by Martin Pool
- Merge aaron's merge command
96
    if status not in (0, 1):
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
97
        raise Exception(stderr)
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
98
    f = open(out_file, 'wb')
99
    try:
100
        f.write(output)
101
    finally:
102
        f.close()
493 by Martin Pool
- Merge aaron's merge command
103
    return status