line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package SVN::Rami;
|
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
213329
|
use 5.10.1;
|
|
2
|
|
|
|
|
18
|
|
4
|
2
|
|
|
2
|
|
11
|
use strict;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
43
|
|
5
|
2
|
|
|
2
|
|
9
|
use warnings;
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
63
|
|
6
|
|
|
|
|
|
|
|
7
|
2
|
|
|
2
|
|
13
|
use File::Basename;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
257
|
|
8
|
2
|
|
|
2
|
|
14
|
use File::Path qw(make_path remove_tree);
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
3237
|
|
9
|
|
|
|
|
|
|
#use File::Spec; # Will use later for Windows file names.
|
10
|
|
|
|
|
|
|
#use Path::Class; # Will use later for Windows file names.
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# TODO: clearly define the words "version", "revision", "branch". (Maybe "version" isn't the right word to use.)
|
13
|
|
|
|
|
|
|
# TODO: sanitize version names: they should contain only \w and hyphen.
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 NAME
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
SVN::Rami - Automates merging to multiple branches
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=cut
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our $VERSION = '0.202';
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
Used by the script L. This is not (yet) a stand-alone module.
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
There are currently no publicly available methods because
|
32
|
|
|
|
|
|
|
this module is only intended to be used by the script
|
33
|
|
|
|
|
|
|
L.
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=cut
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
#
|
38
|
|
|
|
|
|
|
#Reads a two-column CSV file and converts it to key-value pairs.
|
39
|
|
|
|
|
|
|
#For example, if the file contains one line consisting of "a,b",
|
40
|
|
|
|
|
|
|
#this method returns a mapping of "a" to "b".
|
41
|
|
|
|
|
|
|
#The file is assumed to have no headers.
|
42
|
|
|
|
|
|
|
#
|
43
|
|
|
|
|
|
|
#BUG: the file must be formatted precisely right: even an empty
|
44
|
|
|
|
|
|
|
#line in the middle of the file will result in an incorrect mapping.
|
45
|
|
|
|
|
|
|
#
|
46
|
|
|
|
|
|
|
#TODO: use Text::CSV instead.
|
47
|
|
|
|
|
|
|
#
|
48
|
|
|
|
|
|
|
sub load_csv_as_map {
|
49
|
0
|
|
|
0
|
0
|
0
|
my $filename = shift;
|
50
|
0
|
|
|
|
|
0
|
local $/ = undef; # Slurp mode
|
51
|
0
|
0
|
|
|
|
0
|
open(my $handle, '<', $filename) or die "Could not read $filename\n";
|
52
|
0
|
|
|
|
|
0
|
$_ = <$handle>;
|
53
|
0
|
|
|
|
|
0
|
close $handle;
|
54
|
0
|
|
|
|
|
0
|
my @contents = split( /,|\R/ );
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Hack: the first two items are column headings.
|
57
|
0
|
|
|
|
|
0
|
(undef, undef, my @result) = @contents;
|
58
|
0
|
|
|
|
|
0
|
return @result;
|
59
|
|
|
|
|
|
|
}
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head1 AUTHOR
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
Dan Richter, C<< >>
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=head1 BUGS
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through
|
68
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll
|
69
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes.
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head1 SUPPORT
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command.
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
perldoc SVN::Rami
|
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
You can also look for information at:
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=over 4
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here)
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
L
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=item * CPAN Ratings
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
L
|
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=item * Search CPAN
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
L
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=back
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head1 SEE ALSO
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
SVK::Merge
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT
|
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
This software is copyright (c) 2023 by Dan Richter.
|
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under
|
108
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself.
|
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=cut
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
#
|
114
|
|
|
|
|
|
|
# This utility function simply dumps data to a file.
|
115
|
|
|
|
|
|
|
# Example: write_file('foo.txt', 'Hello world') creates a file
|
116
|
|
|
|
|
|
|
# named foo.txt whose complete contents are "Hello world".
|
117
|
|
|
|
|
|
|
# Note that you can pass a multi-line string as the second argument.
|
118
|
|
|
|
|
|
|
#
|
119
|
|
|
|
|
|
|
sub write_file {
|
120
|
0
|
|
|
0
|
0
|
0
|
my $filename = shift;
|
121
|
0
|
|
|
|
|
0
|
my $contents = shift;
|
122
|
|
|
|
|
|
|
|
123
|
0
|
0
|
|
|
|
0
|
open(my $handle, '>', $filename) or die "Could not write to $filename\n";
|
124
|
0
|
|
|
|
|
0
|
print $handle $contents;
|
125
|
0
|
|
|
|
|
0
|
close $handle;
|
126
|
|
|
|
|
|
|
}
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
#
|
129
|
|
|
|
|
|
|
# Usage: find_revision($revision, %branch_to_url)
|
130
|
|
|
|
|
|
|
# Queries SVN for information about the revision.
|
131
|
|
|
|
|
|
|
# Returns a hash that maps 'branch' to the branch on which the revision
|
132
|
|
|
|
|
|
|
# was committed (e.g., 6.2) and that maps 'commit_message' to the
|
133
|
|
|
|
|
|
|
# comment the user wrote to explain the commit.
|
134
|
|
|
|
|
|
|
#
|
135
|
|
|
|
|
|
|
sub find_revision {
|
136
|
0
|
|
|
0
|
0
|
0
|
my $rev = shift;
|
137
|
0
|
|
|
|
|
0
|
my %branch_to_url = @_;
|
138
|
0
|
|
|
|
|
0
|
foreach my $branch (keys %branch_to_url) {
|
139
|
0
|
|
|
|
|
0
|
my $url = $branch_to_url{$branch};
|
140
|
0
|
|
|
|
|
0
|
$_ = `svn log -c $rev $url`;
|
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# If the revision was NOT on $branch, then the output
|
143
|
|
|
|
|
|
|
# will be a single line of dashes: ----------
|
144
|
|
|
|
|
|
|
#
|
145
|
|
|
|
|
|
|
# But if the revision WAS on $branch, then
|
146
|
|
|
|
|
|
|
# the output will be something like this:
|
147
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
148
|
|
|
|
|
|
|
# r84187 | bob.smith | 2023-03-27 10:53:40 -0400 (Mon, 27 Mar 2023) | 4 lines
|
149
|
|
|
|
|
|
|
#
|
150
|
|
|
|
|
|
|
# Fixed memory leak
|
151
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
152
|
0
|
0
|
|
|
|
0
|
if ( m/^-----+\R* # match a bunch of dashes followed by a newline.
|
153
|
|
|
|
|
|
|
^r.*?lines?\R+ # match line: r84187 | badelman | ... | 4 lines
|
154
|
|
|
|
|
|
|
^(.*?)\R+ # Match the commit message.
|
155
|
|
|
|
|
|
|
^-------+\R*\Z # Match a bunch of dashes followed by a newline.
|
156
|
|
|
|
|
|
|
/msx ) {
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
#if ( m/^-+\r?\n?.*?lines(\r?\n)+(.*?)\r?\n-+(\r?\n)*$/sx ) {
|
159
|
0
|
|
|
|
|
0
|
return ('branch'=>$branch, 'commit_message'=>$1 );
|
160
|
|
|
|
|
|
|
}
|
161
|
|
|
|
|
|
|
}
|
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# Revision not found. Return an empty hash.
|
164
|
0
|
|
|
|
|
0
|
return ();
|
165
|
|
|
|
|
|
|
}
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# HACK: define these as essentially global for now.
|
169
|
|
|
|
|
|
|
our $repo = 'default'; # TODO: support more than one repo.
|
170
|
|
|
|
|
|
|
our $rami_home_dir = glob("~/.rami/repo/$repo"); # TODO: use File::HomeDir instead of ~/
|
171
|
|
|
|
|
|
|
our $conf_dir = "$rami_home_dir/conf";
|
172
|
|
|
|
|
|
|
our $temp_dir = "$rami_home_dir/temp";
|
173
|
|
|
|
|
|
|
our $commit_message_file = "$temp_dir/message.txt";
|
174
|
|
|
|
|
|
|
our $path_csv_file = "$conf_dir/paths.csv"; # Not currently used.
|
175
|
|
|
|
|
|
|
our $root_work_dir = "$rami_home_dir/work"; # Holds a subdirectory for each branch.
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
#=head2 rami_main
|
179
|
|
|
|
|
|
|
#
|
180
|
|
|
|
|
|
|
#The main module. Currently takes one argument,
|
181
|
|
|
|
|
|
|
#which is the SVN revision which shoulde be merged.
|
182
|
|
|
|
|
|
|
#
|
183
|
|
|
|
|
|
|
#=cut
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub rami_main {
|
186
|
0
|
|
|
0
|
0
|
0
|
my $source_revision = shift;
|
187
|
|
|
|
|
|
|
|
188
|
0
|
|
|
|
|
0
|
my $conf_dir = $SVN::Rami::conf_dir;
|
189
|
0
|
|
|
|
|
0
|
my $commit_message_file = $SVN::Rami::commit_message_file;
|
190
|
0
|
|
|
|
|
0
|
my $path_csv_file = $SVN::Rami::path_csv_file;
|
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
#print "### $commit_message_file\n";
|
193
|
|
|
|
|
|
|
|
194
|
0
|
0
|
|
|
|
0
|
die "Expected directory $conf_dir\n" unless -d $conf_dir;
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# my %branch_to_path_on_filesystem = load_csv_as_map($path_csv_file);
|
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# We need the list of branches to be in order.
|
199
|
0
|
|
|
|
|
0
|
my @branch_to_url_array = load_csv_as_map("$conf_dir/urls.csv");
|
200
|
0
|
|
|
|
|
0
|
my %branch_to_url = @branch_to_url_array;
|
201
|
0
|
|
|
|
|
0
|
my @branches = grep( !/^http/, @branch_to_url_array); # HACK: remove URLs, leaving only versions, IN ORDER!
|
202
|
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
0
|
my %branch_to_path_on_filesystem = map { $_ => convert_branches_to_filesystem_paths($_) } @branches;
|
|
0
|
|
|
|
|
0
|
|
204
|
|
|
|
|
|
|
|
205
|
0
|
|
|
|
|
0
|
my %revision_details = find_revision($source_revision, %branch_to_url);
|
206
|
0
|
0
|
|
|
|
0
|
if ( ! %revision_details ) {
|
207
|
0
|
|
|
|
|
0
|
die "Unable to find revision $source_revision\n";
|
208
|
|
|
|
|
|
|
}
|
209
|
|
|
|
|
|
|
|
210
|
0
|
|
|
|
|
0
|
my $source_branch = $revision_details{'branch'};
|
211
|
|
|
|
|
|
|
# The revision comment. We will later append something like "merge r 123 from 2.2.2"
|
212
|
0
|
|
|
|
|
0
|
my $base_commit_message = $revision_details{'commit_message'};
|
213
|
0
|
|
|
|
|
0
|
$base_commit_message =~ s/(\r\n\R\s)+$//g; # Remove trailing whitespace/newlines.
|
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
0
|
my $found_branch = 0; # Will be true when we loop to the source branch.
|
217
|
|
|
|
|
|
|
#my $previous_branch = '';
|
218
|
0
|
|
|
|
|
0
|
foreach my $target_branch (@branches) {
|
219
|
0
|
0
|
|
|
|
0
|
if ($target_branch eq $source_branch) {
|
|
|
0
|
|
|
|
|
|
220
|
0
|
|
|
|
|
0
|
$found_branch = 1;
|
221
|
|
|
|
|
|
|
# Perhaps instead of if-else we could use "redo", which is similar to Java's "continue"
|
222
|
|
|
|
|
|
|
} elsif ( $found_branch ) { # If we found the branch last time...
|
223
|
0
|
|
|
|
|
0
|
print "------------------------ Merging r $source_revision from $source_branch to $target_branch\n";
|
224
|
0
|
|
|
|
|
0
|
my $source_url = $branch_to_url{$source_branch};
|
225
|
0
|
|
|
|
|
0
|
my $working_dir = $branch_to_path_on_filesystem{$target_branch};
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# Get our working directory to the correct revision.
|
228
|
0
|
|
|
|
|
0
|
chdir($working_dir);
|
229
|
0
|
|
|
|
|
0
|
system("svn revert -R ."); # or die "Failed to revert $working_dir";
|
230
|
0
|
|
|
|
|
0
|
system("svn up"); # or die "Failed to update $working_dir";
|
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# Write the commit message to a file.
|
233
|
0
|
|
|
|
|
0
|
my $commit_message = "$base_commit_message (merge r $source_revision from $source_branch)";
|
234
|
0
|
|
|
|
|
0
|
write_file($commit_message_file, $commit_message);
|
235
|
|
|
|
|
|
|
|
236
|
0
|
|
|
|
|
0
|
my $merge_command = "svn merge --accept postpone -c $source_revision $source_url .";
|
237
|
0
|
|
|
|
|
0
|
print "$merge_command\n";
|
238
|
0
|
|
|
|
|
0
|
my $output_from_merge = `$merge_command`;
|
239
|
0
|
|
|
|
|
0
|
print "$output_from_merge\n";
|
240
|
0
|
0
|
|
|
|
0
|
if ($output_from_merge =~ /Summary of conflicts/) { # If there were merge conflicts
|
241
|
0
|
|
|
|
|
0
|
print "Failed to merge r $source_revision from $source_branch to $target_branch.\n";
|
242
|
0
|
|
|
|
|
0
|
print "Merge conflicts in $working_dir\n";
|
243
|
0
|
|
|
|
|
0
|
die;
|
244
|
|
|
|
|
|
|
}
|
245
|
|
|
|
|
|
|
|
246
|
0
|
|
|
|
|
0
|
my $commit_command = "svn commit --file $commit_message_file";
|
247
|
0
|
|
|
|
|
0
|
print "$commit_command\n";
|
248
|
0
|
|
|
|
|
0
|
my $output_from_commit = `$commit_command`;
|
249
|
0
|
|
|
|
|
0
|
my $target_revision;
|
250
|
0
|
|
|
|
|
0
|
print "$output_from_commit\n";
|
251
|
0
|
0
|
|
|
|
0
|
if ($output_from_commit =~ /Committed revision (\d+)\./) {
|
252
|
0
|
|
|
|
|
0
|
$target_revision = $1;
|
253
|
|
|
|
|
|
|
} else {
|
254
|
0
|
|
|
|
|
0
|
die "Failed to commit r $source_revision from $source_branch to $target_branch.\n";
|
255
|
|
|
|
|
|
|
}
|
256
|
|
|
|
|
|
|
|
257
|
0
|
|
|
|
|
0
|
$source_branch = $target_branch;
|
258
|
0
|
|
|
|
|
0
|
$source_revision = $target_revision;
|
259
|
|
|
|
|
|
|
} else {
|
260
|
0
|
|
|
|
|
0
|
print "Skipping branch $target_branch because we don't need to merge it.\n";
|
261
|
|
|
|
|
|
|
}
|
262
|
|
|
|
|
|
|
}
|
263
|
|
|
|
|
|
|
|
264
|
0
|
0
|
|
|
|
0
|
if ( ! $found_branch ) {
|
265
|
0
|
|
|
|
|
0
|
die "Unrecognized branch $source_branch\n";
|
266
|
|
|
|
|
|
|
}
|
267
|
|
|
|
|
|
|
}
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
#=head2 load_config_from_SVN_url
|
270
|
|
|
|
|
|
|
#
|
271
|
|
|
|
|
|
|
#Secondary function: initializes based on a configuration
|
272
|
|
|
|
|
|
|
#file which is loaded from SVN.
|
273
|
|
|
|
|
|
|
#Takes one argument, which is the name of the config file.
|
274
|
|
|
|
|
|
|
#
|
275
|
|
|
|
|
|
|
#=cut
|
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
sub load_config_from_SVN_url {
|
278
|
0
|
|
|
0
|
0
|
0
|
my $svn_url = shift; # URL of our config file in SVN.
|
279
|
0
|
|
|
|
|
0
|
my $rami_home_dir = $SVN::Rami::rami_home_dir;
|
280
|
0
|
|
|
|
|
0
|
my $conf_dir = $SVN::Rami::conf_dir;
|
281
|
0
|
|
|
|
|
0
|
my $temp_dir = $SVN::Rami::temp_dir;
|
282
|
0
|
|
|
|
|
0
|
my $root_work_dir = $SVN::Rami::root_work_dir;
|
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# TODO: don't wipe out the old configuration until we know that the new configuration exists.
|
285
|
|
|
|
|
|
|
|
286
|
0
|
0
|
|
|
|
0
|
remove_tree $rami_home_dir if -d $rami_home_dir;
|
287
|
0
|
|
|
|
|
0
|
make_path $conf_dir, $temp_dir, $root_work_dir;
|
288
|
|
|
|
|
|
|
|
289
|
0
|
|
|
|
|
0
|
my $result_of_export = EXEC("svn export --force $svn_url $conf_dir");
|
290
|
0
|
0
|
|
|
|
0
|
die "Failed to load configuration from SVN\n" unless ($result_of_export =~ m/Export complete|Exported revision/);
|
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# Load the branches.
|
293
|
|
|
|
|
|
|
# This code is COPY-AND-PASTED from rami_main().
|
294
|
0
|
|
|
|
|
0
|
my @branch_to_url_array = load_csv_as_map("$conf_dir/urls.csv");
|
295
|
0
|
|
|
|
|
0
|
my %branch_to_url = @branch_to_url_array;
|
296
|
0
|
|
|
|
|
0
|
my @branches = grep( !/^http/, @branch_to_url_array); # HACK: remove URLs, leaving only versions, IN ORDER!
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# Checkout the branches onto the local filesystem.
|
299
|
0
|
|
|
|
|
0
|
while (my($branch,$url) = each(%branch_to_url)) {
|
300
|
0
|
|
|
|
|
0
|
my $filesystem_path = convert_branches_to_filesystem_paths($branch);
|
301
|
0
|
|
|
|
|
0
|
my $command = "svn checkout $url $filesystem_path";
|
302
|
0
|
|
|
|
|
0
|
print "$command\n";
|
303
|
0
|
|
|
|
|
0
|
system($command);
|
304
|
|
|
|
|
|
|
}
|
305
|
|
|
|
|
|
|
}
|
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
#
|
308
|
|
|
|
|
|
|
# Converts a list of logical branch names to the place on the filesystem where they should be.
|
309
|
|
|
|
|
|
|
#
|
310
|
|
|
|
|
|
|
# Example: convert_branches_to_filesystem_paths('trunk')
|
311
|
|
|
|
|
|
|
# might return '/home/bob/.rami/repo/default/work/bob'
|
312
|
|
|
|
|
|
|
#
|
313
|
|
|
|
|
|
|
# In list context, returns a list.
|
314
|
|
|
|
|
|
|
# In scalar context, returns the first item of the list.
|
315
|
|
|
|
|
|
|
#
|
316
|
|
|
|
|
|
|
sub convert_branches_to_filesystem_paths {
|
317
|
2
|
|
|
2
|
0
|
132
|
my $rami_home_dir = $SVN::Rami::rami_home_dir;
|
318
|
2
|
|
|
|
|
7
|
my @result = map { "$rami_home_dir/work/$_" } @_;
|
|
3
|
|
|
|
|
12
|
|
319
|
2
|
100
|
|
|
|
15
|
return wantarray ? @result : $result[0];
|
320
|
|
|
|
|
|
|
}
|
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
#
|
323
|
|
|
|
|
|
|
# Executes on the command line and returns the output.
|
324
|
|
|
|
|
|
|
# Example: my $list = EXEC('ls');
|
325
|
|
|
|
|
|
|
#
|
326
|
|
|
|
|
|
|
# This is just a wrapper for back-tick, i.e.,
|
327
|
|
|
|
|
|
|
# my $result = `$command`;
|
328
|
|
|
|
|
|
|
# but it might later allow us to unit-test.
|
329
|
|
|
|
|
|
|
#
|
330
|
|
|
|
|
|
|
sub EXEC {
|
331
|
0
|
|
|
0
|
0
|
|
my $command = shift;
|
332
|
|
|
|
|
|
|
# my %args = ...
|
333
|
0
|
|
|
|
|
|
print "$command\n";
|
334
|
0
|
|
|
|
|
|
my $result = `$command`;
|
335
|
0
|
|
|
|
|
|
print "$result\n";
|
336
|
0
|
|
|
|
|
|
return $result;
|
337
|
|
|
|
|
|
|
}
|
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
1; # End of SVN::Rami
|