~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
6379.6.3 by Jelmer Vernooij
Use absolute_import.
17
from __future__ import absolute_import
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
18
1534.7.130 by Aaron Bentley
More conflict handling, test porting
19
import errno
493 by Martin Pool
- Merge aaron's merge command
20
import os
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
21
from subprocess import Popen, PIPE
1534.7.130 by Aaron Bentley
More conflict handling, test porting
22
23
from bzrlib.errors import NoDiff3
1558.15.3 by Aaron Bentley
Handle binary files for diff3 merges
24
from bzrlib.textfile import check_text_path
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
25
26
"""Diff and patch functionality"""
27
493 by Martin Pool
- Merge aaron's merge command
28
__docformat__ = "restructuredtext"
29
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
30
31
_do_close_fds = True
32
if os.name == 'nt':
33
    _do_close_fds = False
34
35
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
36
def write_to_cmd(args, input=""):
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
37
    """Spawn a process, and wait for the result
38
39
    If the process is killed, an exception is raised
40
41
    :param args: The command line, the first entry should be the program name
42
    :param input: [optional] The text to send the process on stdin
43
    :return: (stdout, stderr, status)
44
    """
45
    process = Popen(args, bufsize=len(input), stdin=PIPE, stdout=PIPE,
46
                    stderr=PIPE, close_fds=_do_close_fds)
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
47
    stdout, stderr = process.communicate(input)
48
    status = process.wait()
49
    if status < 0:
50
        raise Exception("%s killed by signal %i" (args[0], -status))
51
    return stdout, stderr, status
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
52
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
53
493 by Martin Pool
- Merge aaron's merge command
54
def patch(patch_contents, filename, output_filename=None, reverse=False):
55
    """Apply a patch to a file, to produce another output file.  This is should
56
    be suitable for our limited purposes.
57
58
    :param patch_contents: The contents of the patch to apply
59
    :type patch_contents: str
60
    :param filename: the name of the file to apply the patch to
61
    :type filename: str
62
    :param output_filename: The filename to produce.  If None, file is \
63
    modified in-place
64
    :type output_filename: str or NoneType
65
    :param reverse: If true, apply the patch in reverse
66
    :type reverse: bool
67
    :return: 0 on success, 1 if some hunks failed
68
    """
69
    args = ["patch", "-f", "-s", "--posix", "--binary"]
70
    if reverse:
71
        args.append("--reverse")
72
    if output_filename is not None:
73
        args.extend(("-o", output_filename))
74
    args.append(filename)
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
75
    stdout, stderr, status = write_to_cmd(args, patch_contents)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
76
    return status
493 by Martin Pool
- Merge aaron's merge command
77
78
79
def diff3(out_file, mine_path, older_path, yours_path):
80
    def add_label(args, label):
81
        args.extend(("-L", label))
1558.15.3 by Aaron Bentley
Handle binary files for diff3 merges
82
    check_text_path(mine_path)
83
    check_text_path(older_path)
84
    check_text_path(yours_path)
493 by Martin Pool
- Merge aaron's merge command
85
    args = ['diff3', "-E", "--merge"]
86
    add_label(args, "TREE")
87
    add_label(args, "ANCESTOR")
88
    add_label(args, "MERGE-SOURCE")
89
    args.extend((mine_path, older_path, yours_path))
1534.7.130 by Aaron Bentley
More conflict handling, test porting
90
    try:
91
        output, stderr, status = write_to_cmd(args)
92
    except OSError, e:
93
        if e.errno == errno.ENOENT:
94
            raise NoDiff3
95
        else:
96
            raise
493 by Martin Pool
- Merge aaron's merge command
97
    if status not in (0, 1):
974.1.2 by Aaron Bentley
Replaced popen with subprocess in patch..py
98
        raise Exception(stderr)
1711.7.20 by John Arbash Meinel
always close files, minor PEP8 cleanup
99
    f = open(out_file, 'wb')
100
    try:
101
        f.write(output)
102
    finally:
103
        f.close()
493 by Martin Pool
- Merge aaron's merge command
104
    return status