~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")
27
    return bzrlib.Branch(dirname, init=True)
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
35
    >>> br = temp_branch()
36
    >>> is_clean(br)
37
    True
38
    >>> fooname = os.path.join(br.base, "foo")
39
    >>> file(fooname, "wb").write("bar")
40
    >>> is_clean(br)
41
    False
42
    >>> bzrlib.add.smart_add([fooname])
43
    >>> is_clean(br)
44
    False
45
    >>> br.commit("added file")
46
    >>> is_clean(br)
47
    True
48
    >>> rm_branch(br)
49
    """
95 by Aaron Bentley
Updated to use compare_trees directly from diff
50
    from bzrlib.diff import compare_trees
16 by abentley
Got is_clean under test, added setters/getters for pull data
51
    old_tree = cur_branch.basis_tree()
52
    new_tree = cur_branch.working_tree()
117 by aaron.bentley at utoronto
Excluded non-source files
53
    non_source = []
41 by Aaron Bentley
Adapted to new ways of checking for clean tree
54
    for path, file_class, kind, file_id in new_tree.list_files():
117 by aaron.bentley at utoronto
Excluded non-source files
55
        if file_class in ('?', 'I'):
56
            non_source.append(path)
95 by Aaron Bentley
Updated to use compare_trees directly from diff
57
    delta = compare_trees(old_tree, new_tree, want_unchanged=False)
42 by Aaron Bentley
Got tree check working with new API
58
    if len(delta.added) > 0 or len(delta.removed) > 0 or \
59
        len(delta.modified) > 0:
117 by aaron.bentley at utoronto
Excluded non-source files
60
        return False, non_source
61
    return True, non_source 
16 by abentley
Got is_clean under test, added setters/getters for pull data
62
63
def set_pull_data(br, location, rev_id):
19 by abentley
librified most of the pull script
64
    pull_file = file (br.controlfilename("x-pull-data"), "wb")
16 by abentley
Got is_clean under test, added setters/getters for pull data
65
    pull_file.write("%s\n%s\n" % (location, rev_id))
66
67
def get_pull_data(br):
68
    """
69
    >>> br = temp_branch()
70
    >>> get_pull_data(br)
71
    (None, None)
72
    >>> set_pull_data(br, 'http://somewhere', '888-777')
73
    >>> get_pull_data(br)
74
    ('http://somewhere', '888-777')
75
    >>> rm_branch(br)
76
    """
19 by abentley
librified most of the pull script
77
    filename = br.controlfilename("x-pull-data")
16 by abentley
Got is_clean under test, added setters/getters for pull data
78
    if not os.path.exists(filename):
79
        return (None, None)
80
    pull_file = file (filename, "rb")
81
    location, rev_id = [f.rstrip('\n') for f in pull_file]
82
    return location, rev_id
83
20 by abentley
added bzr-push command
84
def set_push_data(br, location):
85
    push_file = file (br.controlfilename("x-push-data"), "wb")
86
    push_file.write("%s\n" % location)
87
88
def get_push_data(br):
89
    """
90
    >>> br = temp_branch()
91
    >>> get_push_data(br) is None
92
    True
93
    >>> set_push_data(br, 'http://somewhere')
94
    >>> get_push_data(br)
95
    'http://somewhere'
96
    >>> rm_branch(br)
97
    """
98
    filename = br.controlfilename("x-push-data")
99
    if not os.path.exists(filename):
100
        return None
101
    push_file = file (filename, "rb")
102
    (location,) = [f.rstrip('\n') for f in push_file]
103
    return location
104
19 by abentley
librified most of the pull script
105
"""
106
>>> shell_escape('hello')
107
'\h\e\l\l\o'
108
"""
109
def shell_escape(arg):
110
    return "".join(['\\'+c for c in arg])
111
112
def safe_system(args):
113
    """
114
    >>> real_system = os.system
115
    >>> os.system = sys.stdout.write
116
    >>> safe_system(['a', 'b', 'cd'])
117
    \\a \\b \\c\\d
118
    >>> os.system = real_system
119
    """
120
    arg_str = " ".join([shell_escape(a) for a in args])
121
    return os.system(arg_str)
122
117 by aaron.bentley at utoronto
Excluded non-source files
123
def rsync(source, target, ssh=False, excludes=()):
19 by abentley
librified most of the pull script
124
    """
125
    >>> real_system = os.system
126
    >>> os.system = sys.stdout.write
127
    >>> rsync("a", "b")
128
    \\r\\s\\y\\n\\c \\-\\a\\v \\-\\-\\d\\e\\l\\e\\t\\e \\a \\b
117 by aaron.bentley at utoronto
Excluded non-source files
129
    >>> rsync("a", "b", excludes=("*.py",))
25 by abentley
fixed push for x files, tracefile, push/pull miscommunication
130
    \\r\\s\\y\\n\\c \\-\\a\\v \\-\\-\\d\\e\\l\\e\\t\\e\
131
 \\-\\-\\e\\x\\c\\l\\u\\d\\e \\*\\.\\p\\y \\a \\b
19 by abentley
librified most of the pull script
132
    >>> os.system = real_system
133
    """
20 by abentley
added bzr-push command
134
    cmd = ["rsync", "-av", "--delete"]
135
    if ssh:
136
        cmd.extend(('-e', 'ssh'))
117 by aaron.bentley at utoronto
Excluded non-source files
137
    if len(excludes) > 0:
138
        cmd.extend(('--exclude-from', '-'))
20 by abentley
added bzr-push command
139
    cmd.extend((source, target))
117 by aaron.bentley at utoronto
Excluded non-source files
140
    proc = Popen(cmd, stdin=PIPE)
141
    proc.stdin.write('\n'.join(excludes)+'\n')
142
    proc.stdin.close()
143
    return proc.wait()
144
145
exclusions = ('.bzr/x-push-data', '.bzr/x-pull-data', '.bzr/stat-cache')
19 by abentley
librified most of the pull script
146
20 by abentley
added bzr-push command
147
148
def push(cur_branch, location=None):
149
    push_location = get_push_data(cur_branch)
150
    if location is not None:
25 by abentley
fixed push for x files, tracefile, push/pull miscommunication
151
        if not location.endswith('/'):
152
            location += '/'
20 by abentley
added bzr-push command
153
        push_location = location
154
    
155
    if push_location is None:
156
        print "No push location saved.  Please specify one on the command line."
157
        sys.exit(1)
158
117 by aaron.bentley at utoronto
Excluded non-source files
159
    clean, non_source = is_clean(cur_branch)
160
    if not clean:
88 by Aaron Bentley
Added suggestion to use 'bzr status' to push error.
161
        print """Error: This tree has uncommitted changes or unknown (?) files.
162
Use "bzr status" to list them."""
20 by abentley
added bzr-push command
163
        sys.exit(1)
117 by aaron.bentley at utoronto
Excluded non-source files
164
    non_source.extend(exclusions)
20 by abentley
added bzr-push command
165
166
    print "Pushing to %s" % push_location
117 by aaron.bentley at utoronto
Excluded non-source files
167
    rsync(cur_branch.base+'/', push_location, ssh=True, excludes=non_source)
20 by abentley
added bzr-push command
168
169
    set_push_data(cur_branch, push_location)
170
19 by abentley
librified most of the pull script
171
def run_tests():
16 by abentley
Got is_clean under test, added setters/getters for pull data
172
    import doctest
18 by abentley
Finished implementing bzr-pull
173
    result = doctest.testmod()
19 by abentley
librified most of the pull script
174
    if result[1] > 0:
175
        if result[0] == 0:
176
            print "All tests passed"
177
    else:
178
        print "No tests to run"
179
if __name__ == "__main__":
180
    run_tests()