Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1293 dpurdie 1
###############################################################################
2
# Codestriker: Copyright (c) 2001,2002,2003 David Sitsky.  All rights reserved.
3
# sits@users.sourceforge.net
4
#
5
# This program is free software; you can redistribute it and modify it under
6
# the terms of the GPL.
7
 
8
# Subversion repository access package.
9
 
10
package Codestriker::Repository::Subversion;
11
use IPC::Open3;
12
 
13
use strict;
14
use Fatal qw / open close /;
15
 
16
# Constructor, which takes as a parameter the repository url.
17
sub new {
18
    my ($type, $repository_url, $user, $password) = @_;
19
 
20
    # Determine if there are additional parameters required for user
21
    # authentication.
22
    my @userCmdLine = ();
23
    if (defined($user) && defined($password)) {
24
        push @userCmdLine, '--username';
1299 dpurdie 25
        push @userCmdLine, $user;
26
        push @userCmdLine, '--password';
27
        push @userCmdLine, $password;
1293 dpurdie 28
    }
29
 
30
    # Sanitise the repository URL.
31
    $repository_url = sanitise_url_component($repository_url);
32
 
33
    my $self = {};
34
    $self->{repository_url} = $repository_url;
35
    $self->{userCmdLine} = \@userCmdLine;
36
    $self->{repository_string} = $repository_url;
37
    $self->{repository_string} .= ";$user" if defined $user;
38
    $self->{repository_string} .= ";$password" if defined $password;
39
    if ($self->{repository_string} !~ /^svn:/) {
1299 dpurdie 40
        $self->{repository_string} = "svn:" . $self->{repository_string};
1293 dpurdie 41
    }
42
 
43
    bless $self, $type;
44
}
45
 
46
# Sanitise a Subversion URL component, by replacing spaces with %20 and @
47
# symbols with %40, so that there is no confused with pegged revisions.  Also
48
# remove any leading and trailing slashes.
49
sub sanitise_url_component {
50
    my $url = shift;
51
    $url =~ s/\/$//;
52
    $url =~ s/^\///;
53
    $url =~ s/ /%20/g;
54
    $url =~ s/\@/%40/g;
55
    return $url;
56
}
57
 
58
# Retrieve the data corresponding to $filename and $revision.  Store each line
59
# into $content_array_ref.
60
sub retrieve ($$$\$) {
61
    my ($self, $filename, $revision, $content_array_ref) = @_;
62
 
63
    # Sanitise the filename.
64
    $filename = sanitise_url_component($filename);
65
 
66
    my $read_data;
67
    my $read_stdout_fh = new FileHandle;
68
    open($read_stdout_fh, '>', \$read_data);
69
    my @args = ();
70
    push @args, 'cat';
71
    push @args, '--non-interactive';
72
    push @args, '--no-auth-cache';
1299 dpurdie 73
    push @args, '--trust-server-cert';
1293 dpurdie 74
    push @args, @{ $self->{userCmdLine} };
75
    push @args, '--revision';
76
    push @args, $revision;
77
    push @args, $self->{repository_url} . '/' . $filename;
78
    Codestriker::execute_command($read_stdout_fh, undef,
1299 dpurdie 79
                                 $Codestriker::svn, @args);
1293 dpurdie 80
 
81
    # Process the data for the topic.
82
    open($read_stdout_fh, '<', \$read_data);
83
    for (my $i = 1; <$read_stdout_fh>; $i++) {
1299 dpurdie 84
        $_ = Codestriker::decode_topic_text($_);
85
        chop;
86
        $$content_array_ref[$i] = $_;
1293 dpurdie 87
    }
88
}
89
 
90
# Retrieve the "root" of this repository.
91
sub getRoot ($) {
92
    my ($self) = @_;
93
    return $self->{repository_url};
94
}
95
 
96
# Return a URL which views the specified file and revision.
97
sub getViewUrl ($$$) {
98
    my ($self, $filename, $revision) = @_;
99
 
100
    # Lookup the file viewer from the configuration.
101
    my $viewer = $Codestriker::file_viewer->{$self->toString()};
102
    if (! (defined $viewer)) {
1299 dpurdie 103
        $viewer = $Codestriker::file_viewer->{$self->{repository_string}};
1293 dpurdie 104
    }
105
 
106
    return (defined $viewer) ? $viewer . "/" . $filename : "";
107
}
108
 
109
# Return a string representation of this repository.
110
sub toString ($) {
111
    my ($self) = @_;
112
    return "svn:" . $self->getRoot();
113
}
114
 
115
# Given a Subversion URL, determine if it refers to a directory or a file.
116
sub is_file_url {
117
    my ($self, $url) = @_;
118
    my $file_url;
119
 
120
    eval {
1299 dpurdie 121
        my @args = ();
122
        push @args, 'info';
123
        push @args, '--non-interactive';
124
        push @args, '--no-auth-cache';
125
        push @args, '--trust-server-cert';
126
        push @args, @{ $self->{userCmdLine} };
127
        push @args, '--xml';
128
        push @args, $self->{repository_url} . '/' . $url;
129
        my $read_data;
130
        my $read_stdout_fh = new FileHandle;
131
        open($read_stdout_fh, '>', \$read_data);
1293 dpurdie 132
 
1299 dpurdie 133
        Codestriker::execute_command($read_stdout_fh, undef,
134
                                     $Codestriker::svn, @args);
135
        open($read_stdout_fh, '<', \$read_data);
136
        while (<$read_stdout_fh>) {
137
            if (/kind\s*\=\s*\"(\w+)\"/) {
138
                $file_url = $1 eq "File";
139
                last;
140
            }
141
        }
1293 dpurdie 142
    };
143
    if ($@ || !(defined $file_url)) {
1299 dpurdie 144
        # The above command failed, try using the older method which only works
145
        # in an English locale.  This supports Subversion 1.2 or earlier
146
        # releases, which don't support the --xml flag for the info command.
147
        my @args = ();
148
        push @args, 'cat';
149
        push @args, '--non-interactive';
150
        push @args, '--no-auth-cache';
151
        push @args, '--trust-server-cert';
152
        push @args, @{ $self->{userCmdLine} };
153
        push @args, '--revision';
154
        push @args, 'HEAD';
155
        push @args, $self->{repository_url} . '/' . $url;
1293 dpurdie 156
 
1299 dpurdie 157
        my $read_stdout_data;
158
        my $read_stdout_fh = new FileHandle;
159
        open($read_stdout_fh, '>', \$read_stdout_data);
1293 dpurdie 160
 
1299 dpurdie 161
        my $read_stderr_data;
162
        my $read_stderr_fh = new FileHandle;
163
        open($read_stderr_fh, '>', \$read_stderr_data);
1293 dpurdie 164
 
1299 dpurdie 165
        Codestriker::execute_command($read_stdout_fh, $read_stderr_fh,
166
                                     $Codestriker::svn, @args);
167
        $file_url = 1;
168
        open($read_stderr_fh, '<', \$read_stderr_data);
169
        while(<$read_stderr_fh>) {
170
            if (/^svn:.* refers to a directory/) {
171
                $file_url = 0;
172
                last;
173
            }
174
        }
1293 dpurdie 175
    }
176
 
177
    return $file_url;
178
}
179
 
180
# The getDiff operation, pull out a change set based on the start and end 
181
# revision number, confined to the specified moduled_name.
182
sub getDiff {
183
    my ($self, $start_tag, $end_tag, $module_name, $stdout_fh, $stderr_fh) = @_;
184
 
185
    # Sanitise the URL, and determine if it refers to a directory or filename.
186
    $module_name = sanitise_url_component($module_name);
187
    my $directory;
188
    if ($self->is_file_url($module_name)) {
1299 dpurdie 189
        $module_name =~ /(.*)\/[^\/]+/;
190
        $directory = $1;
1293 dpurdie 191
    } else {
1299 dpurdie 192
        $directory = $module_name;
1293 dpurdie 193
    }
194
 
195
    # Execute the diff command.
196
    my $read_stdout_data;
197
    my $read_stdout_fh = new FileHandle;
198
    open($read_stdout_fh, '>', \$read_stdout_data);
199
 
200
    my @args = ();
201
    push @args, 'diff';
202
    push @args, '--non-interactive';
203
    push @args, '--no-auth-cache';
1299 dpurdie 204
    push @args, '--trust-server-cert';
1293 dpurdie 205
    push @args, @{ $self->{userCmdLine} };
206
    push @args, '-r';
207
    push @args, $start_tag . ':' . $end_tag;
208
    push @args, '--old';
209
    push @args, $self->{repository_url};
210
    push @args, $module_name;
211
    Codestriker::execute_command($read_stdout_fh, $stderr_fh,
1299 dpurdie 212
                                 $Codestriker::svn, @args);
1293 dpurdie 213
 
214
    open($read_stdout_fh, '<', \$read_stdout_data);
215
    while(<$read_stdout_fh>) {
1299 dpurdie 216
        my $line = $_;
217
 
218
        # If the user specifies a path (a branch in Subversion), the
219
        # diff file does not come back with a path rooted from the
220
        # repository base making it impossible to pull the entire file
221
        # back out. This code attempts to change the diff file on the
222
        # fly to ensure that the full path is present. This is a bug
223
        # against Subversion, so eventually it will be fixed, so this
224
        # code can't break when the diff command starts returning the
225
        # full path.
226
        if ($line =~ /^--- / || $line =~ /^\+\+\+ / ||
227
            $line =~ /^Index: /) {
228
            # Check if the bug has been fixed.
229
            if ($line =~ /^\+\+\+ $module_name/ == 0 && 
230
                $line =~ /^--- $module_name/ == 0 &&
231
                $line =~ /^Index: $module_name/ == 0) {
232
                    $line =~ s/^--- /--- $directory\// or
233
                    $line =~ s/^Index: /Index: $directory\// or
234
                    $line =~ s/^\+\+\+ /\+\+\+ $directory\//;
235
            }
236
        }
1293 dpurdie 237
 
1299 dpurdie 238
        print $stdout_fh $line;
1293 dpurdie 239
    }
240
 
241
    return $Codestriker::OK;
242
}
243
 
244
1;