rscm 0.2.1.1404 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +34 -23
- data/Rakefile +24 -29
- data/bin/touch.exe +0 -0
- data/lib/rscm.rb +6 -3
- data/lib/rscm/annotations.rb +26 -7
- data/lib/rscm/{abstract_scm.rb → base.rb} +109 -71
- data/lib/rscm/better.rb +16 -0
- data/lib/rscm/logging.rb +11 -5
- data/lib/rscm/path_converter.rb +9 -16
- data/lib/rscm/revision.rb +201 -0
- data/lib/rscm/revision_file.rb +71 -0
- data/lib/rscm/scm/clearcase.rb +7 -7
- data/lib/rscm/scm/cvs.rb +69 -70
- data/lib/rscm/scm/cvs_log_parser.rb +29 -29
- data/lib/rscm/scm/darcs.rb +82 -34
- data/lib/rscm/scm/darcs_log_parser.rb +65 -0
- data/lib/rscm/scm/monotone.rb +249 -77
- data/lib/rscm/scm/monotone_log_parser.rb +57 -43
- data/lib/rscm/scm/mooky.rb +3 -3
- data/lib/rscm/scm/perforce.rb +196 -134
- data/lib/rscm/scm/star_team.rb +10 -10
- data/lib/rscm/scm/subversion.rb +106 -77
- data/lib/rscm/scm/subversion_log_parser.rb +76 -47
- data/lib/rscm/time_ext.rb +2 -116
- data/test/rscm/annotations_test.rb +15 -2
- data/test/rscm/{abstract_scm_test.rb → base_test.rb} +3 -3
- data/test/rscm/difftool_test.rb +9 -3
- data/test/rscm/generic_scm_tests.rb +195 -124
- data/test/rscm/revision_fixture.rb +20 -0
- data/test/rscm/revision_test.rb +129 -0
- data/test/rscm/{changesets.yaml → revisions.yaml} +10 -10
- data/test/rscm/scm/clearcase.log +608 -0
- data/test/rscm/scm/clearcase_test.rb +39 -0
- data/test/rscm/scm/cvs_log_parser_test.rb +73 -73
- data/test/rscm/scm/cvs_test.rb +1 -1
- data/test/rscm/scm/darcs_log_parser_test.rb +171 -0
- data/test/rscm/scm/monotone_log_parser_test.rb +49 -31
- data/test/rscm/scm/monotone_test.rb +3 -2
- data/test/rscm/scm/p4client_test.rb +33 -0
- data/test/rscm/scm/perforce_test.rb +25 -3
- data/test/rscm/scm/star_team.rb +9 -9
- data/test/rscm/scm/subversion_log_parser_test.rb +107 -47
- metadata +17 -13
- data/lib/multipart.rb +0 -95
- data/lib/rscm/RSS.txt +0 -41
- data/lib/rscm/changes.rb +0 -268
- data/lib/rscm/example.yaml +0 -21
- data/lib/rubyforge_file_publisher.rb +0 -176
- data/test/rscm/changes_fixture.rb +0 -20
- data/test/rscm/changes_test.rb +0 -129
data/lib/rscm/scm/star_team.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'tempfile'
|
3
|
-
require 'rscm/
|
4
|
-
require 'rscm/
|
3
|
+
require 'rscm/revision'
|
4
|
+
require 'rscm/base'
|
5
5
|
require 'yaml'
|
6
6
|
|
7
7
|
class Time
|
@@ -17,8 +17,8 @@ module RSCM
|
|
17
17
|
# * StarTeam SDK
|
18
18
|
# * Apache Ant (http://ant.apache.org/)
|
19
19
|
#
|
20
|
-
class StarTeam <
|
21
|
-
register self
|
20
|
+
class StarTeam < Base
|
21
|
+
#register self
|
22
22
|
|
23
23
|
ann :description => "User name"
|
24
24
|
attr_accessor :user_name
|
@@ -49,23 +49,23 @@ module RSCM
|
|
49
49
|
"StarTeam"
|
50
50
|
end
|
51
51
|
|
52
|
-
def
|
52
|
+
def revisions(checkout_dir, from_identifier=Time.epoch, to_identifier=Time.infinity, &proc)
|
53
53
|
# just assuming it is a Time for now, may support labels later.
|
54
54
|
# the java class really wants rfc822 and not rfc2822, but this works ok anyway.
|
55
55
|
from = from_identifier.to_rfc2822
|
56
56
|
to = to_identifier.to_rfc2822
|
57
57
|
|
58
|
-
|
59
|
-
raise "
|
58
|
+
revisions = java("getRevisions(\"#{from}\";\"#{to}\")", &proc)
|
59
|
+
raise "revisions must be of type #{Revisions.name} - was #{revisions.class.name}" unless revisions.is_a?(::RSCM::Revisions)
|
60
60
|
|
61
61
|
# Just a little sanity check
|
62
|
-
if(
|
63
|
-
latetime =
|
62
|
+
if(revisions.latest)
|
63
|
+
latetime = revisions.latest.time
|
64
64
|
if(latetime < from_identifier || to_identifier < latetime)
|
65
65
|
raise "Latest time (#{latetime}) is not within #{from_identifier}-#{to_identifier}"
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
68
|
+
revisions
|
69
69
|
end
|
70
70
|
|
71
71
|
def checkout(checkout_dir, to_identifier, &proc)
|
data/lib/rscm/scm/subversion.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'rscm/
|
1
|
+
require 'rscm/base'
|
2
2
|
require 'rscm/path_converter'
|
3
3
|
require 'rscm/line_editor'
|
4
4
|
require 'rscm/scm/subversion_log_parser'
|
@@ -10,22 +10,29 @@ module RSCM
|
|
10
10
|
# You need the svn/svnadmin executable on the PATH in order for it to work.
|
11
11
|
#
|
12
12
|
# NOTE: On Cygwin these have to be the win32 builds of svn/svnadmin and not the Cygwin ones.
|
13
|
-
class Subversion <
|
13
|
+
class Subversion < Base
|
14
14
|
register self
|
15
15
|
|
16
16
|
include FileUtils
|
17
17
|
include PathConverter
|
18
18
|
|
19
19
|
ann :description => "Repository URL"
|
20
|
-
# ann :tip => "If you specify a local URL (starting with file://) DamageControl can create the repository for you after you save (unless the repository already exists).<br>Using a file:// URL will also give you the option to have DamageControl install a trigger in Subversion, so that you don't have to use polling to detect changes.<br>On Windows, file URLs must look like file:///C:/jupiter/mars"
|
21
20
|
ann :tip => "If you use ssh, specify the URL as svn+ssh://username@server/path/to/repo"
|
22
21
|
attr_accessor :url
|
23
22
|
|
23
|
+
ann :description => "Username"
|
24
|
+
ann :tip => "This only applies to svn:// URLs."
|
25
|
+
attr_accessor :username
|
26
|
+
|
27
|
+
ann :description => "Password"
|
28
|
+
ann :tip => "This only applies to svn:// URLs."
|
29
|
+
attr_accessor :password
|
30
|
+
|
24
31
|
ann :description => "Path"
|
25
|
-
ann :tip => "This
|
32
|
+
ann :tip => "You only need to specify this if you want to be able to automatically create the repository. This should be the relative path from the start of the repository <br>to the end of the URL. For example, if your URL is <br>svn://your.server/path/to/repository/path/within/repository <br>then this value should be path/within/repository."
|
26
33
|
attr_accessor :path
|
27
34
|
|
28
|
-
def initialize(url="", path="
|
35
|
+
def initialize(url="", path="")
|
29
36
|
@url, @path = url, path
|
30
37
|
end
|
31
38
|
|
@@ -33,21 +40,21 @@ module RSCM
|
|
33
40
|
"Subversion"
|
34
41
|
end
|
35
42
|
|
36
|
-
def add(
|
37
|
-
svn(checkout_dir, "add #{relative_filename}")
|
43
|
+
def add(relative_filename)
|
44
|
+
svn(@checkout_dir, "add #{relative_filename}")
|
38
45
|
end
|
39
46
|
|
40
47
|
def transactional?
|
41
48
|
true
|
42
49
|
end
|
43
50
|
|
44
|
-
def checkout(
|
45
|
-
checkout_dir = PathConverter.filepath_to_nativepath(checkout_dir, false)
|
46
|
-
mkdir_p(checkout_dir)
|
51
|
+
def checkout(to_identifier=nil)
|
52
|
+
checkout_dir = PathConverter.filepath_to_nativepath(@checkout_dir, false)
|
53
|
+
mkdir_p(@checkout_dir)
|
47
54
|
checked_out_files = []
|
48
55
|
path_regex = /^[A|D|U]\s+(.*)/
|
49
|
-
if(checked_out?
|
50
|
-
svn(checkout_dir, update_command(to_identifier)) do |line|
|
56
|
+
if(checked_out?)
|
57
|
+
svn(@checkout_dir, update_command(to_identifier)) do |line|
|
51
58
|
if(line =~ path_regex)
|
52
59
|
absolute_path = "#{checkout_dir}/#{$1}"
|
53
60
|
relative_path = $1.chomp
|
@@ -57,14 +64,15 @@ module RSCM
|
|
57
64
|
end
|
58
65
|
end
|
59
66
|
else
|
60
|
-
svn(checkout_dir, checkout_command(
|
67
|
+
svn(@checkout_dir, checkout_command(to_identifier)) do |line|
|
61
68
|
if(line =~ path_regex)
|
62
69
|
native_absolute_path = $1
|
63
|
-
|
64
|
-
absolute_path = PathConverter.nativepath_to_filepath($1)
|
65
|
-
native_checkout_dir = PathConverter.filepath_to_nativepath(checkout_dir, false)
|
70
|
+
absolute_path = PathConverter.nativepath_to_filepath(native_absolute_path)
|
66
71
|
if(File.exist?(absolute_path) && !File.directory?(absolute_path))
|
67
|
-
|
72
|
+
native_checkout_dir = PathConverter.filepath_to_nativepath(@checkout_dir, false)
|
73
|
+
# relative_path = native_absolute_path[native_checkout_dir.length+1..-1].chomp
|
74
|
+
# not sure about this old code - this seems to work. keep it here till it's verified on win32
|
75
|
+
relative_path = absolute_path
|
68
76
|
relative_path = relative_path.gsub(/\\/, "/") if WINDOWS
|
69
77
|
checked_out_files << relative_path
|
70
78
|
yield relative_path if block_given?
|
@@ -83,60 +91,43 @@ module RSCM
|
|
83
91
|
"svn update #{url} #{checkout_dir}"
|
84
92
|
end
|
85
93
|
|
86
|
-
def uptodate?(
|
87
|
-
if(!checked_out?
|
94
|
+
def uptodate?(identifier)
|
95
|
+
if(!checked_out?)
|
88
96
|
false
|
89
97
|
else
|
90
|
-
|
91
|
-
|
92
|
-
lr == hr
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def local_revision(checkout_dir)
|
97
|
-
local_revision = nil
|
98
|
-
svn(checkout_dir, "info") do |line|
|
99
|
-
if(line =~ /Revision: ([0-9]*)/)
|
100
|
-
return $1.to_i
|
101
|
-
end
|
98
|
+
rev = identifier ? identifier : head_revision_identifier
|
99
|
+
local_revision_identifier == rev
|
102
100
|
end
|
103
101
|
end
|
104
102
|
|
105
|
-
def
|
106
|
-
|
107
|
-
with_working_dir(checkout_dir) do
|
108
|
-
safer_popen(cmd) do |stdout|
|
109
|
-
parser = SubversionLogParser.new(stdout, path, checkout_dir)
|
110
|
-
changesets = parser.parse_changesets
|
111
|
-
changesets[0].revision.to_i
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def commit(checkout_dir, message)
|
117
|
-
svn(checkout_dir, commit_command(message))
|
103
|
+
def commit(message)
|
104
|
+
svn(@checkout_dir, commit_command(message))
|
118
105
|
# We have to do an update to get the local revision right
|
119
|
-
svn(checkout_dir, "update")
|
106
|
+
svn(@checkout_dir, "update")
|
120
107
|
end
|
121
108
|
|
122
|
-
def label
|
123
|
-
|
109
|
+
def label
|
110
|
+
local_revision_identifier.to_s
|
124
111
|
end
|
125
112
|
|
126
|
-
def diff(
|
127
|
-
with_working_dir(checkout_dir) do
|
128
|
-
cmd = "svn diff -r #{
|
129
|
-
|
113
|
+
def diff(file, &block)
|
114
|
+
with_working_dir(@checkout_dir) do
|
115
|
+
cmd = "svn diff -r #{file.previous_native_revision_identifier}:#{file.native_revision_identifier} \"#{url}/#{file.path}\""
|
116
|
+
Better.popen(cmd) do |io|
|
130
117
|
return(yield(io))
|
131
118
|
end
|
132
119
|
end
|
133
120
|
end
|
134
121
|
|
135
|
-
def
|
122
|
+
def can_create_central?
|
136
123
|
local?
|
137
124
|
end
|
138
125
|
|
139
|
-
def
|
126
|
+
def destroy_central
|
127
|
+
FileUtils.rm_rf(svnrootdir)
|
128
|
+
end
|
129
|
+
|
130
|
+
def central_exists?
|
140
131
|
if(local?)
|
141
132
|
File.exists?("#{svnrootdir}/db")
|
142
133
|
else
|
@@ -145,7 +136,7 @@ module RSCM
|
|
145
136
|
# on stdout (and an error msg on std err).
|
146
137
|
exists = false
|
147
138
|
cmd = "svn log #{url} -r HEAD"
|
148
|
-
|
139
|
+
Better.popen(cmd) do |stdout|
|
149
140
|
stdout.each_line do |line|
|
150
141
|
exists = true
|
151
142
|
end
|
@@ -158,7 +149,7 @@ module RSCM
|
|
158
149
|
local?
|
159
150
|
end
|
160
151
|
|
161
|
-
def
|
152
|
+
def create_central
|
162
153
|
native_path = PathConverter.filepath_to_nativepath(svnrootdir, true)
|
163
154
|
mkdir_p(PathConverter.nativepath_to_filepath(native_path))
|
164
155
|
svnadmin(svnrootdir, "create #{native_path}")
|
@@ -182,27 +173,27 @@ module RSCM
|
|
182
173
|
not_already_commented
|
183
174
|
end
|
184
175
|
|
185
|
-
def
|
176
|
+
def import_central(dir, message)
|
186
177
|
import_cmd = "import #{url} -m \"#{message}\""
|
187
178
|
svn(dir, import_cmd)
|
188
179
|
end
|
189
180
|
|
190
|
-
def
|
191
|
-
# Return empty
|
192
|
-
return
|
181
|
+
def revisions(from_identifier, to_identifier=Time.infinity)
|
182
|
+
# Return empty revision if the requested revision doesn't exist yet.
|
183
|
+
return Revisions.new if(from_identifier.is_a?(Integer) && head_revision_identifier <= from_identifier)
|
193
184
|
|
194
|
-
checkout_dir = PathConverter.filepath_to_nativepath(checkout_dir, false)
|
195
|
-
|
185
|
+
checkout_dir = PathConverter.filepath_to_nativepath(@checkout_dir, false)
|
186
|
+
revisions = nil
|
196
187
|
command = "svn #{changes_command(from_identifier, to_identifier)}"
|
197
188
|
yield command if block_given?
|
198
189
|
|
199
|
-
with_working_dir(checkout_dir) do
|
200
|
-
|
201
|
-
parser = SubversionLogParser.new(stdout,
|
202
|
-
|
190
|
+
with_working_dir(@checkout_dir) do
|
191
|
+
Better.popen(command) do |stdout|
|
192
|
+
parser = SubversionLogParser.new(stdout, @url)
|
193
|
+
revisions = parser.parse_revisions
|
203
194
|
end
|
204
195
|
end
|
205
|
-
|
196
|
+
revisions
|
206
197
|
end
|
207
198
|
|
208
199
|
# url pointing to the root of the repo
|
@@ -211,7 +202,7 @@ module RSCM
|
|
211
202
|
url[0..last]
|
212
203
|
end
|
213
204
|
|
214
|
-
def checked_out?
|
205
|
+
def checked_out?
|
215
206
|
rootentries = File.expand_path("#{checkout_dir}/.svn/entries")
|
216
207
|
result = File.exists?(rootentries)
|
217
208
|
result
|
@@ -219,6 +210,30 @@ module RSCM
|
|
219
210
|
|
220
211
|
private
|
221
212
|
|
213
|
+
def local_revision_identifier
|
214
|
+
local_revision_identifier = nil
|
215
|
+
svn(@checkout_dir, "info") do |line|
|
216
|
+
if(line =~ /Revision: ([0-9]*)/)
|
217
|
+
return $1.to_i
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def head_revision_identifier
|
223
|
+
# This command only seems to yield any changesets if the url is the root of
|
224
|
+
# the repo, which we don't know in the case where path is not specified (likely)
|
225
|
+
# We therefore don't specify it and get the latest revision from the full url instead.
|
226
|
+
# cmd = "svn log #{login_options} #{repourl} -r HEAD"
|
227
|
+
cmd = "svn log #{login_options} #{url}"
|
228
|
+
with_working_dir(@checkout_dir) do
|
229
|
+
Better.popen(cmd) do |stdout|
|
230
|
+
parser = SubversionLogParser.new(stdout, @url)
|
231
|
+
revisions = parser.parse_revisions
|
232
|
+
revisions[0].identifier.to_i
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
222
237
|
def install_unix_trigger(trigger_command, damagecontrol_install_dir)
|
223
238
|
post_commit_exists = File.exists?(post_commit_file)
|
224
239
|
mode = post_commit_exists ? File::APPEND|File::WRONLY : File::CREAT|File::WRONLY
|
@@ -227,7 +242,7 @@ module RSCM
|
|
227
242
|
file.puts("#!/bin/sh") unless post_commit_exists
|
228
243
|
file.puts("#{trigger_command}\n" )
|
229
244
|
end
|
230
|
-
|
245
|
+
File.chmod(0744, post_commit_file)
|
231
246
|
rescue
|
232
247
|
raise "Didn't have permission to write to #{post_commit_file}. " +
|
233
248
|
"Try to manually add the following line:\n\n#{trigger_command}\n\n" +
|
@@ -265,7 +280,7 @@ module RSCM
|
|
265
280
|
command_line = "#{executable} #{cmd}"
|
266
281
|
dir = File.expand_path(dir)
|
267
282
|
with_working_dir(dir) do
|
268
|
-
|
283
|
+
Better.popen(command_line) do |stdout|
|
269
284
|
stdout.each_line do |line|
|
270
285
|
yield line if block_given?
|
271
286
|
end
|
@@ -273,36 +288,50 @@ module RSCM
|
|
273
288
|
end
|
274
289
|
end
|
275
290
|
|
276
|
-
def checkout_command(
|
291
|
+
def checkout_command(to_identifier)
|
277
292
|
checkout_dir = "\"#{checkout_dir}\""
|
278
|
-
"checkout #{url} #{checkout_dir} #{revision_option(nil,to_identifier)}"
|
293
|
+
"checkout #{login_options} #{url} #{checkout_dir} #{revision_option(nil,to_identifier)}"
|
279
294
|
end
|
280
295
|
|
281
296
|
def update_command(to_identifier)
|
282
|
-
"update #{revision_option(nil,to_identifier)}"
|
297
|
+
"update #{login_options} #{revision_option(nil,to_identifier)}"
|
283
298
|
end
|
284
299
|
|
285
300
|
def changes_command(from_identifier, to_identifier)
|
286
301
|
# http://svnbook.red-bean.com/svnbook-1.1/svn-book.html#svn-ch-3-sect-3.3
|
287
302
|
# file_list = files.join('\n')
|
288
303
|
# WEIRD cygwin bug garbles this!?!?!?!
|
289
|
-
cmd = "log --verbose #{revision_option(from_identifier, to_identifier)} #{url}"
|
304
|
+
cmd = "log --verbose #{login_options} #{revision_option(from_identifier, to_identifier)} #{url}"
|
290
305
|
cmd
|
291
306
|
end
|
292
307
|
|
308
|
+
def login_options
|
309
|
+
result = ""
|
310
|
+
u = @username ? @username.strip : nil
|
311
|
+
p = @password ? @password.strip : nil
|
312
|
+
result << "--username #{u} " if u
|
313
|
+
result << "--password #{p} " if p
|
314
|
+
result
|
315
|
+
end
|
316
|
+
|
293
317
|
def revision_option(from_identifier, to_identifier)
|
318
|
+
# The inclusive start
|
294
319
|
from = nil
|
295
320
|
if(from_identifier.is_a?(Time))
|
296
|
-
from = svndate(from_identifier)
|
297
|
-
|
298
|
-
from = from_identifier
|
321
|
+
from = svndate(from_identifier + 1)
|
322
|
+
elsif(from_identifier.is_a?(Numeric))
|
323
|
+
from = from_identifier + 1
|
324
|
+
elsif(!from_identifier.nil?)
|
325
|
+
raise "from_identifier must be Numeric, Time or nil. Was: #{from_identifier} (#{from_identifier.class.name})"
|
299
326
|
end
|
300
327
|
|
301
328
|
to = nil
|
302
329
|
if(to_identifier.is_a?(Time))
|
303
330
|
to = svndate(to_identifier)
|
304
|
-
|
331
|
+
elsif(to_identifier.is_a?(Numeric))
|
305
332
|
to = to_identifier
|
333
|
+
elsif(!from_identifier.nil?)
|
334
|
+
raise "to_identifier must be Numeric, Time or nil. Was: #{to_identifier} (#{to_identifier.class.name})"
|
306
335
|
end
|
307
336
|
|
308
337
|
revision_option = nil
|
@@ -1,108 +1,137 @@
|
|
1
1
|
require 'rscm/parser'
|
2
|
-
require 'rscm/
|
2
|
+
require 'rscm/revision'
|
3
3
|
|
4
4
|
module RSCM
|
5
5
|
|
6
6
|
class SubversionLogParser
|
7
|
-
def initialize(io,
|
7
|
+
def initialize(io, url)
|
8
8
|
@io = io
|
9
|
-
@
|
9
|
+
@revision_parser = SubversionLogEntryParser.new(url)
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def parse_revisions(&line_proc)
|
13
13
|
# skip over the first ------
|
14
|
-
@
|
15
|
-
|
14
|
+
@revision_parser.parse(@io, true, &line_proc)
|
15
|
+
revisions = Revisions.new
|
16
16
|
while(!@io.eof?)
|
17
|
-
|
18
|
-
if(
|
19
|
-
|
17
|
+
revision = @revision_parser.parse(@io, &line_proc)
|
18
|
+
if(revision)
|
19
|
+
revisions.add(revision)
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
revisions
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
class SubversionLogEntryParser < Parser
|
27
27
|
|
28
|
-
def initialize(
|
28
|
+
def initialize(url)
|
29
29
|
super(/^------------------------------------------------------------------------/)
|
30
|
-
@
|
31
|
-
@checkout_dir = checkout_dir
|
30
|
+
@url = url
|
32
31
|
end
|
33
32
|
|
34
33
|
def parse(io, skip_line_parsing=false, &line_proc)
|
35
34
|
# We have to trim off the last newline - it's not meant to be part of the message
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
revision = super
|
36
|
+
revision.message = revision.message[0..-2] if revision
|
37
|
+
revision
|
39
38
|
end
|
40
39
|
|
40
|
+
def relative_path(url, repo_path)
|
41
|
+
url_tokens = url.split('/')
|
42
|
+
repo_path_tokens = repo_path.split('/')
|
43
|
+
|
44
|
+
max_similar = repo_path_tokens.length
|
45
|
+
while(max_similar > 0)
|
46
|
+
url = url_tokens[-max_similar..-1]
|
47
|
+
path = repo_path_tokens[0..max_similar-1]
|
48
|
+
if(url == path)
|
49
|
+
break
|
50
|
+
end
|
51
|
+
max_similar -= 1
|
52
|
+
end
|
53
|
+
max_similar == 0 ? nil : repo_path_tokens[max_similar..-1].join("/")
|
54
|
+
end
|
55
|
+
|
41
56
|
protected
|
42
57
|
|
43
58
|
def parse_line(line)
|
44
|
-
if(@
|
59
|
+
if(@revision.nil?)
|
45
60
|
parse_header(line)
|
46
61
|
elsif(line.strip == "")
|
47
62
|
@parse_state = :parse_message
|
48
63
|
elsif(line =~ /Changed paths/)
|
49
|
-
@parse_state = :
|
50
|
-
elsif(@parse_state == :
|
51
|
-
|
52
|
-
if
|
53
|
-
|
54
|
-
|
55
|
-
|
64
|
+
@parse_state = :parse_files
|
65
|
+
elsif(@parse_state == :parse_files)
|
66
|
+
file = parse_file(line)
|
67
|
+
if(file)
|
68
|
+
previously_added_file = @revision[-1]
|
69
|
+
if(previously_added_file)
|
70
|
+
# remove previous revision_file it if it's a dir
|
71
|
+
previous_tokens = previously_added_file.path.split("/")
|
72
|
+
current_tokens = file.path.split("/")
|
73
|
+
current_tokens.pop
|
74
|
+
if(previous_tokens == current_tokens)
|
75
|
+
@revision.pop
|
76
|
+
end
|
77
|
+
end
|
78
|
+
@revision << file
|
56
79
|
end
|
57
80
|
elsif(@parse_state == :parse_message)
|
58
|
-
@
|
81
|
+
@revision.message << line.chomp << "\n"
|
59
82
|
end
|
60
83
|
end
|
61
84
|
|
62
85
|
def next_result
|
63
|
-
result = @
|
64
|
-
@
|
86
|
+
result = @revision
|
87
|
+
@revision = nil
|
65
88
|
result
|
66
89
|
end
|
67
90
|
|
68
91
|
private
|
69
92
|
|
70
|
-
STATES = {"M" =>
|
93
|
+
STATES = {"M" => RevisionFile::MODIFIED, "A" => RevisionFile::ADDED, "D" => RevisionFile::DELETED} unless defined? STATES
|
71
94
|
|
72
95
|
def parse_header(line)
|
73
|
-
@
|
74
|
-
@
|
96
|
+
@revision = Revision.new
|
97
|
+
@revision.message = ""
|
75
98
|
revision, developer, time, the_rest = line.split("|")
|
76
|
-
@
|
77
|
-
@
|
78
|
-
@
|
99
|
+
@revision.identifier = revision.strip[1..-1].to_i unless revision.nil?
|
100
|
+
@revision.developer = developer.strip unless developer.nil?
|
101
|
+
@revision.time = parse_time(time.strip) unless time.nil?
|
79
102
|
end
|
80
103
|
|
81
|
-
def
|
82
|
-
|
104
|
+
def parse_file(line)
|
105
|
+
file = RevisionFile.new
|
83
106
|
path_from_root = nil
|
84
107
|
if(line =~ /^ [M|A|D|R] ([^\s]+) \(from (.*)\)/)
|
85
108
|
path_from_root = $1
|
86
|
-
|
109
|
+
file.status = RevisionFile::MOVED
|
87
110
|
elsif(line =~ /^ ([M|A|D|R]) (.+)$/)
|
88
111
|
status = $1
|
89
112
|
path_from_root = $2
|
90
|
-
|
113
|
+
file.status = STATES[status]
|
91
114
|
else
|
92
|
-
raise "could not parse
|
115
|
+
raise "could not parse file line: '#{line}'"
|
93
116
|
end
|
94
117
|
|
95
118
|
path_from_root.gsub!(/\\/, "/")
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
119
|
+
path_from_root = path_from_root[1..-1]
|
120
|
+
rp = relative_path(@url, path_from_root)
|
121
|
+
return if rp.nil?
|
122
|
+
file.path = rp
|
123
|
+
|
124
|
+
|
125
|
+
# if(@path.length+1 == path_from_root.length)
|
126
|
+
# file.path = path_from_root[@path.length+1..-1]
|
127
|
+
# else
|
128
|
+
# file.path = path_from_root[@path.length+2..-1]
|
129
|
+
# end
|
130
|
+
|
131
|
+
file.native_revision_identifier = @revision.identifier
|
103
132
|
# http://jira.codehaus.org/browse/DC-204
|
104
|
-
|
105
|
-
|
133
|
+
file.previous_native_revision_identifier = file.native_revision_identifier.to_i - 1;
|
134
|
+
file
|
106
135
|
end
|
107
136
|
|
108
137
|
def parse_time(svn_time)
|