~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to bzrtools.py

  • Committer: Aaron Bentley
  • Date: 2012-01-20 02:00:40 UTC
  • Revision ID: aaron@aaronbentley.com-20120120020040-7y4c93fhnnahidxg
Remove rspush

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Aaron Bentley
2
 
# <aaron.bentley@utoronto.ca>
 
1
# Copyright (C) 2005-2009, 2011-2012 Aaron Bentley <aaron@aaronbentley.com>
 
2
# Copyright (C) 2007 John Arbash Meinel
3
3
#
4
4
#    This program is free software; you can redistribute it and/or modify
5
5
#    it under the terms of the GNU General Public License as published by
14
14
#    You should have received a copy of the GNU General Public License
15
15
#    along with this program; if not, write to the Free Software
16
16
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 
import bzrlib
18
17
import os
19
 
import os.path
20
 
import sys
 
18
import re
21
19
import tempfile
22
20
import shutil
23
 
from subprocess import Popen, PIPE
24
 
 
25
 
def temp_branch():
26
 
    dirname = tempfile.mkdtemp("temp-branch")
27
 
    return bzrlib.branch.Branch.initialize(dirname)
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
 
    >>> import bzrlib.add
36
 
    >>> br = temp_branch()
37
 
    >>> is_clean(br)
38
 
    (True, [])
39
 
    >>> fooname = os.path.join(br.base, "foo")
40
 
    >>> file(fooname, "wb").write("bar")
41
 
    >>> is_clean(br)
42
 
    (True, ['foo'])
43
 
    >>> bzrlib.add.smart_add_branch(br, [br.base])
44
 
    1
45
 
    >>> is_clean(br)
46
 
    (False, [])
47
 
    >>> br.commit("added file")
48
 
    added foo
49
 
    >>> is_clean(br)
50
 
    (True, [])
51
 
    >>> rm_branch(br)
52
 
    """
53
 
    from bzrlib.diff import compare_trees
54
 
    old_tree = cur_branch.basis_tree()
55
 
    new_tree = cur_branch.working_tree()
56
 
    non_source = []
57
 
    for path, file_class, kind, file_id in new_tree.list_files():
58
 
        if file_class in ('?', 'I'):
59
 
            non_source.append(path)
60
 
    delta = compare_trees(old_tree, new_tree, want_unchanged=False)
61
 
    if len(delta.added) > 0 or len(delta.removed) > 0 or \
62
 
        len(delta.modified) > 0:
63
 
        return False, non_source
64
 
    return True, non_source 
65
 
 
66
 
def set_pull_data(br, location, rev_id):
67
 
    pull_file = file (br.controlfilename("x-pull-data"), "wb")
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
 
    """
80
 
    filename = br.controlfilename("x-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
 
 
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
 
 
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
 
 
126
 
def rsync(source, target, ssh=False, excludes=()):
127
 
    """
128
 
    >>> real_system = os.system
129
 
    >>> os.system = sys.stdout.write
130
 
    >>> rsync("a", "b")
131
 
    ['rsync', '-av', '--delete', 'a', 'b']
132
 
    >>> rsync("a", "b", excludes=("*.py",))
133
 
    ['rsync', '-av', '--delete', '--exclude-from', '-', 'a', 'b']
134
 
    >>> os.system = real_system
135
 
    """
136
 
    cmd = ["rsync", "-av", "--delete"]
137
 
    if ssh:
138
 
        cmd.extend(('-e', 'ssh'))
139
 
    if len(excludes) > 0:
140
 
        cmd.extend(('--exclude-from', '-'))
141
 
    cmd.extend((source, target))
142
 
    proc = Popen(cmd, stdin=PIPE)
143
 
    proc.stdin.write('\n'.join(excludes)+'\n')
144
 
    proc.stdin.close()
145
 
    proc.wait()
146
 
    return cmd
147
 
 
148
 
exclusions = ('.bzr/x-push-data', '.bzr/x-pull-data', '.bzr/stat-cache')
149
 
 
150
 
 
151
 
def push(cur_branch, location=None):
152
 
    push_location = get_push_data(cur_branch)
153
 
    if location is not None:
154
 
        if not location.endswith('/'):
155
 
            location += '/'
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
 
 
162
 
    clean, non_source = is_clean(cur_branch)
163
 
    if not clean:
164
 
        print """Error: This tree has uncommitted changes or unknown (?) files.
165
 
Use "bzr status" to list them."""
166
 
        sys.exit(1)
167
 
    non_source.extend(exclusions)
168
 
 
169
 
    print "Pushing to %s" % push_location
170
 
    rsync(cur_branch.base+'/', push_location, ssh=True, excludes=non_source)
171
 
 
172
 
    set_push_data(cur_branch, push_location)
 
21
 
 
22
from bzrlib import urlutils
 
23
from bzrlib.errors import (
 
24
    BzrCommandError,
 
25
    NotBranchError,
 
26
    NoSuchFile,
 
27
    )
 
28
from bzrlib.bzrdir import BzrDir
 
29
from bzrlib.transport import get_transport
 
30
 
 
31
 
 
32
def short_committer(committer):
 
33
    new_committer = re.sub('<.*>', '', committer).strip(' ')
 
34
    if len(new_committer) < 2:
 
35
        return committer
 
36
    return new_committer
 
37
 
 
38
 
 
39
def apache_ls(t):
 
40
    """Screen-scrape Apache listings"""
 
41
    apache_dir = '<img border="0" src="/icons/folder.gif" alt="[dir]">'\
 
42
        ' <a href="'
 
43
    t = t.clone()
 
44
    t._remote_path = lambda x: t.base
 
45
    try:
 
46
        lines = t.get('')
 
47
    except NoSuchFile:
 
48
        return
 
49
    expr = re.compile('<a[^>]*href="([^>]*)\/"[^>]*>', flags=re.I)
 
50
    for line in lines:
 
51
        match = expr.search(line)
 
52
        if match is None:
 
53
            continue
 
54
        url = match.group(1)
 
55
        if url.startswith('http://') or url.startswith('/') or '../' in url:
 
56
            continue
 
57
        if '?' in url:
 
58
            continue
 
59
        yield url.rstrip('/')
 
60
 
 
61
 
 
62
def list_branches(t):
 
63
    def is_inside(branch):
 
64
        return bool(branch.base.startswith(t.base))
 
65
 
 
66
    if t.base.startswith('http://'):
 
67
        def evaluate(bzrdir):
 
68
            try:
 
69
                branch = bzrdir.open_branch()
 
70
                if is_inside(branch):
 
71
                    return True, branch
 
72
                else:
 
73
                    return True, None
 
74
            except NotBranchError:
 
75
                return True, None
 
76
        return [b for b in BzrDir.find_bzrdirs(t, list_current=apache_ls,
 
77
                evaluate=evaluate) if b is not None]
 
78
    elif not t.listable():
 
79
        raise BzrCommandError("Can't list this type of location.")
 
80
    return [b for b in BzrDir.find_branches(t) if is_inside(b)]
 
81
 
 
82
 
 
83
def evaluate_branch_tree(bzrdir):
 
84
    try:
 
85
        tree, branch = bzrdir._get_tree_branch()
 
86
    except NotBranchError:
 
87
        return True, None
 
88
    else:
 
89
        return True, (branch, tree)
 
90
 
 
91
 
 
92
def iter_branch_tree(t, lister=None):
 
93
    return (x for x in BzrDir.find_bzrdirs(t, evaluate=evaluate_branch_tree,
 
94
            list_current=lister) if x is not None)
 
95
 
 
96
 
 
97
def open_from_url(location):
 
98
    location = urlutils.normalize_url(location)
 
99
    dirname, basename = urlutils.split(location)
 
100
    if location.endswith('/') and not basename.endswith('/'):
 
101
        basename += '/'
 
102
    return get_transport(dirname).get(basename)
 
103
 
173
104
 
174
105
def run_tests():
175
106
    import doctest