~abentley/bzrtools/bzrtools.dev

89 by Aaron Bentley
Added copyright/GPL notices
1
# Copyright (C) 2005 Aaron Bentley
2
# <aaron.bentley@utoronto.ca>
3
#
4
#    This program is free software; you can redistribute it and/or modify
5
#    it under the terms of the GNU General Public License as published by
6
#    the Free Software Foundation; either version 2 of the License, or
7
#    (at your option) any later version.
8
#
9
#    This program is distributed in the hope that it will be useful,
10
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
#    GNU General Public License for more details.
13
#
14
#    You should have received a copy of the GNU General Public License
15
#    along with this program; if not, write to the Free Software
16
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 by abentley
Got is_clean under test, added setters/getters for pull data
17
import bzrlib
19 by abentley
librified most of the pull script
18
import os
16 by abentley
Got is_clean under test, added setters/getters for pull data
19
import os.path
19 by abentley
librified most of the pull script
20
import sys
16 by abentley
Got is_clean under test, added setters/getters for pull data
21
import tempfile
22
import shutil
117 by aaron.bentley at utoronto
Excluded non-source files
23
from subprocess import Popen, PIPE
16 by abentley
Got is_clean under test, added setters/getters for pull data
24
25
def temp_branch():
26
    dirname = tempfile.mkdtemp("temp-branch")
158 by Aaron Bentley
Updated to match API changes
27
    return bzrlib.branch.Branch.initialize(dirname)
16 by abentley
Got is_clean under test, added setters/getters for pull data
28
29
def rm_branch(br):
30
    shutil.rmtree(br.base)
31
32
def is_clean(cur_branch):
33
    """
34
    Return true if no files are modifed or unknown
147 by Robert Collins
make bzr selftest run the plugins tests, and fix them
35
    >>> import bzrlib.add
16 by abentley
Got is_clean under test, added setters/getters for pull data
36
    >>> br = temp_branch()
37
    >>> is_clean(br)
147 by Robert Collins
make bzr selftest run the plugins tests, and fix them
38
    (True, [])
16 by abentley
Got is_clean under test, added setters/getters for pull data
39
    >>> fooname = os.path.join(br.base, "foo")
40
    >>> file(fooname, "wb").write("bar")
41
    >>> is_clean(br)
147 by Robert Collins
make bzr selftest run the plugins tests, and fix them
42
    (True, ['foo'])
43
    >>> bzrlib.add.smart_add_branch(br, [br.base])
44
    1
16 by abentley
Got is_clean under test, added setters/getters for pull data
45
    >>> is_clean(br)
147 by Robert Collins
make bzr selftest run the plugins tests, and fix them
46
    (False, [])
16 by abentley
Got is_clean under test, added setters/getters for pull data
47
    >>> br.commit("added file")
147 by Robert Collins
make bzr selftest run the plugins tests, and fix them
48
    added foo
16 by abentley
Got is_clean under test, added setters/getters for pull data
49
    >>> is_clean(br)
147 by Robert Collins
make bzr selftest run the plugins tests, and fix them
50
    (True, [])
16 by abentley
Got is_clean under test, added setters/getters for pull data
51
    >>> rm_branch(br)
52
    """
95 by Aaron Bentley
Updated to use compare_trees directly from diff
53
    from bzrlib.diff import compare_trees
16 by abentley
Got is_clean under test, added setters/getters for pull data
54
    old_tree = cur_branch.basis_tree()
55
    new_tree = cur_branch.working_tree()
117 by aaron.bentley at utoronto
Excluded non-source files
56
    non_source = []
41 by Aaron Bentley
Adapted to new ways of checking for clean tree
57
    for path, file_class, kind, file_id in new_tree.list_files():
117 by aaron.bentley at utoronto
Excluded non-source files
58
        if file_class in ('?', 'I'):
59
            non_source.append(path)
95 by Aaron Bentley
Updated to use compare_trees directly from diff
60
    delta = compare_trees(old_tree, new_tree, want_unchanged=False)
42 by Aaron Bentley
Got tree check working with new API
61
    if len(delta.added) > 0 or len(delta.removed) > 0 or \
62
        len(delta.modified) > 0:
117 by aaron.bentley at utoronto
Excluded non-source files
63
        return False, non_source
64
    return True, non_source 
16 by abentley
Got is_clean under test, added setters/getters for pull data
65
66
def set_pull_data(br, location, rev_id):
19 by abentley
librified most of the pull script
67
    pull_file = file (br.controlfilename("x-pull-data"), "wb")
16 by abentley
Got is_clean under test, added setters/getters for pull data
68
    pull_file.write("%s\n%s\n" % (location, rev_id))
69
70
def get_pull_data(br):
71
    """
72
    >>> br = temp_branch()
73
    >>> get_pull_data(br)
74
    (None, None)
75
    >>> set_pull_data(br, 'http://somewhere', '888-777')
76
    >>> get_pull_data(br)
77
    ('http://somewhere', '888-777')
78
    >>> rm_branch(br)
79
    """
19 by abentley
librified most of the pull script
80
    filename = br.controlfilename("x-pull-data")
16 by abentley
Got is_clean under test, added setters/getters for pull data
81
    if not os.path.exists(filename):
82
        return (None, None)
83
    pull_file = file (filename, "rb")
84
    location, rev_id = [f.rstrip('\n') for f in pull_file]
85
    return location, rev_id
86
20 by abentley
added bzr-push command
87
def set_push_data(br, location):
88
    push_file = file (br.controlfilename("x-push-data"), "wb")
89
    push_file.write("%s\n" % location)
90
91
def get_push_data(br):
92
    """
93
    >>> br = temp_branch()
94
    >>> get_push_data(br) is None
95
    True
96
    >>> set_push_data(br, 'http://somewhere')
97
    >>> get_push_data(br)
98
    'http://somewhere'
99
    >>> rm_branch(br)
100
    """
101
    filename = br.controlfilename("x-push-data")
102
    if not os.path.exists(filename):
103
        return None
104
    push_file = file (filename, "rb")
105
    (location,) = [f.rstrip('\n') for f in push_file]
106
    return location
107
19 by abentley
librified most of the pull script
108
"""
109
>>> shell_escape('hello')
110
'\h\e\l\l\o'
111
"""
112
def shell_escape(arg):
113
    return "".join(['\\'+c for c in arg])
114
115
def safe_system(args):
116
    """
117
    >>> real_system = os.system
118
    >>> os.system = sys.stdout.write
119
    >>> safe_system(['a', 'b', 'cd'])
120
    \\a \\b \\c\\d
121
    >>> os.system = real_system
122
    """
123
    arg_str = " ".join([shell_escape(a) for a in args])
124
    return os.system(arg_str)
125
117 by aaron.bentley at utoronto
Excluded non-source files
126
def rsync(source, target, ssh=False, excludes=()):
19 by abentley
librified most of the pull script
127
    """
128
    >>> real_system = os.system
129
    >>> os.system = sys.stdout.write
130
    >>> rsync("a", "b")
147 by Robert Collins
make bzr selftest run the plugins tests, and fix them
131
    ['rsync', '-av', '--delete', 'a', 'b']
117 by aaron.bentley at utoronto
Excluded non-source files
132
    >>> rsync("a", "b", excludes=("*.py",))
147 by Robert Collins
make bzr selftest run the plugins tests, and fix them
133
    ['rsync', '-av', '--delete', '--exclude-from', '-', 'a', 'b']
19 by abentley
librified most of the pull script
134
    >>> os.system = real_system
135
    """
20 by abentley
added bzr-push command
136
    cmd = ["rsync", "-av", "--delete"]
137
    if ssh:
138
        cmd.extend(('-e', 'ssh'))
117 by aaron.bentley at utoronto
Excluded non-source files
139
    if len(excludes) > 0:
140
        cmd.extend(('--exclude-from', '-'))
20 by abentley
added bzr-push command
141
    cmd.extend((source, target))
117 by aaron.bentley at utoronto
Excluded non-source files
142
    proc = Popen(cmd, stdin=PIPE)
143
    proc.stdin.write('\n'.join(excludes)+'\n')
144
    proc.stdin.close()
147 by Robert Collins
make bzr selftest run the plugins tests, and fix them
145
    proc.wait()
146
    return cmd
117 by aaron.bentley at utoronto
Excluded non-source files
147
148
exclusions = ('.bzr/x-push-data', '.bzr/x-pull-data', '.bzr/stat-cache')
19 by abentley
librified most of the pull script
149
20 by abentley
added bzr-push command
150
151
def push(cur_branch, location=None):
152
    push_location = get_push_data(cur_branch)
153
    if location is not None:
25 by abentley
fixed push for x files, tracefile, push/pull miscommunication
154
        if not location.endswith('/'):
155
            location += '/'
20 by abentley
added bzr-push command
156
        push_location = location
157
    
158
    if push_location is None:
159
        print "No push location saved.  Please specify one on the command line."
160
        sys.exit(1)
161
117 by aaron.bentley at utoronto
Excluded non-source files
162
    clean, non_source = is_clean(cur_branch)
163
    if not clean:
88 by Aaron Bentley
Added suggestion to use 'bzr status' to push error.
164
        print """Error: This tree has uncommitted changes or unknown (?) files.
165
Use "bzr status" to list them."""
20 by abentley
added bzr-push command
166
        sys.exit(1)
117 by aaron.bentley at utoronto
Excluded non-source files
167
    non_source.extend(exclusions)
20 by abentley
added bzr-push command
168
169
    print "Pushing to %s" % push_location
117 by aaron.bentley at utoronto
Excluded non-source files
170
    rsync(cur_branch.base+'/', push_location, ssh=True, excludes=non_source)
20 by abentley
added bzr-push command
171
172
    set_push_data(cur_branch, push_location)
173
19 by abentley
librified most of the pull script
174
def run_tests():
16 by abentley
Got is_clean under test, added setters/getters for pull data
175
    import doctest
18 by abentley
Finished implementing bzr-pull
176
    result = doctest.testmod()
19 by abentley
librified most of the pull script
177
    if result[1] > 0:
178
        if result[0] == 0:
179
            print "All tests passed"
180
    else:
181
        print "No tests to run"
182
if __name__ == "__main__":
183
    run_tests()