rscm 0.1.0.1338 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +13 -28
- data/Rakefile +25 -24
- data/lib/rscm.rb +1 -6
- data/lib/rscm/abstract_scm.rb +36 -10
- data/lib/rscm/annotations.rb +50 -0
- data/lib/rscm/changes.rb +2 -5
- data/lib/rscm/logging.rb +1 -0
- data/lib/rscm/path_converter.rb +3 -2
- data/lib/rscm/{cvs → scm}/cvs.rb +16 -9
- data/lib/rscm/{cvs → scm}/cvs_log_parser.rb +4 -4
- data/lib/rscm/{darcs → scm}/darcs.rb +6 -3
- data/lib/rscm/scm/monotone.rb +162 -0
- data/lib/rscm/scm/monotone_log_parser.rb +95 -0
- data/lib/rscm/scm/mooky.rb +21 -0
- data/lib/rscm/{perforce → scm}/perforce.rb +7 -4
- data/lib/rscm/{starteam/starteam.rb → scm/star_team.rb} +23 -3
- data/lib/rscm/{svn/svn.rb → scm/subversion.rb} +17 -10
- data/lib/rscm/{svn/svn_log_parser.rb → scm/subversion_log_parser.rb} +8 -7
- data/test/rscm/abstract_scm_test.rb +21 -0
- data/test/rscm/annotations_test.rb +57 -0
- data/test/rscm/changes_fixture.rb +7 -7
- data/test/rscm/changes_test.rb +3 -3
- data/test/rscm/generic_scm_tests.rb +2 -2
- data/test/rscm/{cvs → scm}/cvs-dataforge.log +0 -0
- data/test/rscm/{cvs → scm}/cvs-test.log +0 -0
- data/test/rscm/{cvs → scm}/cvs_log_parser_test.rb +12 -13
- data/test/rscm/{cvs → scm}/cvs_test.rb +7 -7
- data/test/rscm/{darcs → scm}/darcs_test.rb +1 -1
- data/test/rscm/{monotone → scm}/keys +0 -0
- data/test/rscm/scm/monotone_log_parser_test.rb +109 -0
- data/test/rscm/{monotone → scm}/monotone_test.rb +1 -1
- data/test/rscm/{mooky → scm}/mooky_test.rb +1 -1
- data/test/rscm/{perforce → scm}/perforce_test.rb +1 -1
- data/test/rscm/{starteam/starteam_test.rb → scm/star_team.rb} +1 -1
- data/test/rscm/{svn/svn_log_parser_test.rb → scm/subversion_log_parser_test.rb} +25 -10
- data/test/rscm/{svn/svn_test.rb → scm/subversion_test.rb} +4 -5
- data/test/rscm/{svn/cargo-svn.log → scm/svn-cargo.log} +0 -0
- data/test/rscm/scm/svn-growl.log +875 -0
- data/test/rscm/scm/svn-growl2.log +30 -0
- data/test/rscm/{svn/proxytoys-svn.log → scm/svn-proxytoys.log} +0 -0
- metadata +35 -44
- data/lib/rscm/attr_attr.rb +0 -36
- data/lib/rscm/monotone/monotone.rb +0 -107
- data/lib/rscm/mooky/mooky.rb +0 -13
- data/test/actual +0 -3
- data/test/expected +0 -3
- data/test/rscm/attr_attr_test.rb +0 -32
data/README
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
= RSCM - Ruby Source Control Management
|
1
|
+
= RSCM - Ruby Source Control Management (0.2.0)
|
2
2
|
|
3
|
-
RSCM is to SCM what
|
3
|
+
RSCM is to SCM what DBI/JDBC/ODBC are to databases - an SCM-independent API for accessing a wide variety of SCMs. The features are roughly:
|
4
4
|
|
5
5
|
* Check out a working copy (with possibility to specify branch/date/label)
|
6
6
|
* Get changesets (changesets are emulated for non-transactional SCMs like CVS and StarTeam)
|
@@ -27,9 +27,10 @@ If you want the latest and greatest, you can get the sources, which live alongsi
|
|
27
27
|
|
28
28
|
In progress:
|
29
29
|
|
30
|
+
* ClearCase -http://www-306.ibm.com/software/awdtools/clearcase (half way there)
|
30
31
|
* Darcs - http://www.abridgegame.org/darcs (very incomplete)
|
31
32
|
* Monotone - http://www.venge.net/monotone (half way there)
|
32
|
-
|
33
|
+
|
33
34
|
Planned:
|
34
35
|
|
35
36
|
Loads! All of them! How to add support for a new one is described further down in this file.
|
@@ -44,7 +45,7 @@ Here is an example of how to use RSCM to get a list of changesets from a CVS rep
|
|
44
45
|
|
45
46
|
require 'rscm'
|
46
47
|
|
47
|
-
scm = RSCM::
|
48
|
+
scm = RSCM::Subversion.new("svn://some.server/some/path/trunk", "trunk")
|
48
49
|
|
49
50
|
scm.checkout("mycheckout")
|
50
51
|
changesets = scm.changesets("mycheckout", Time.utc(2004, 11, 10, 12, 34, 22))
|
@@ -104,8 +105,8 @@ acceptance test suite for RSCM. By doing this you'll actually follow a TDD
|
|
104
105
|
approach for your new Mooky class - except that the tests are already written
|
105
106
|
for you!
|
106
107
|
|
107
|
-
IMPORTANT NOTE: If your SCM doesn't provide an easy way to create new local repositories
|
108
|
-
|
108
|
+
IMPORTANT NOTE: If your SCM doesn't provide an easy way to create new local repositories
|
109
|
+
(such as with StarTeam) you're probably better off writing the tests from scratch and not
|
109
110
|
include GenericSCMTests. Instead, just make sure you have an SCM repository set up somewhere
|
110
111
|
and write tests to work against that repository. This way you won't be able to pass the
|
111
112
|
generic acceptance test suite, and other people (like the RSCM dev team) will probably
|
@@ -120,11 +121,11 @@ They're just files).
|
|
120
121
|
|
121
122
|
Let's implement the Mooky class. Take a look at.
|
122
123
|
|
123
|
-
lib/rscm/
|
124
|
+
lib/rscm/scm/mooky.rb
|
124
125
|
|
125
126
|
Try running Mooky's test:
|
126
127
|
|
127
|
-
rake test TEST=test/rscm/
|
128
|
+
rake test TEST=test/rscm/scm/mooky_test.rb
|
128
129
|
|
129
130
|
Whoops - we got some failures! It failed because our checkout method returned
|
130
131
|
nothing (nil). Let'see if we can get the a little further by implementing this
|
@@ -151,7 +152,7 @@ should also yield each file name as the execution proceeds).
|
|
151
152
|
Once your checkout command works okay, the test will get you a little further. Just keep
|
152
153
|
on going until all tests pass.
|
153
154
|
|
154
|
-
NOTE: If the SCM doesn't have a command line utility or a 3rd party Ruby API, but instead
|
155
|
+
NOTE: If the SCM doesn't have a command line utility (unlikely) or a 3rd party Ruby API, but instead
|
155
156
|
provides libraries (perhaps in C), then you should consider writing a Ruby C extension
|
156
157
|
instead.
|
157
158
|
|
@@ -159,26 +160,10 @@ If the SCM has a Java interface, you can take the same approach as for StarTeam.
|
|
159
160
|
Java classes for ChangeSets that allow easy interaction between Ruby and Java over YAML.
|
160
161
|
You can reuse these classes for other Java based SCMs (if there are any, I don't know).
|
161
162
|
|
162
|
-
==
|
163
|
-
|
164
|
-
If you're contributing a new SCM it would be nice if you took the time to implement a web interface
|
165
|
-
that can be used to embed it into DamageControl.
|
166
|
-
|
167
|
-
In trunk/damagecontrol, start by creating +app/views/project/_mooky.rhtml+.
|
168
|
-
|
169
|
-
Create a table with 2 columns and a row for each +attr_accessor+ in the Mooky class, preferrably
|
170
|
-
with some explanatory text for the users so they know how to fill it in. See how the tooltips
|
171
|
-
are used in some of the existing implementations.
|
172
|
-
|
173
|
-
You also need a javascript section at the top
|
174
|
-
with a function called +mooky_init()+. This will be called when the page is loaded. If you don't
|
175
|
-
have plans to do anything fancy here, just leave it blank.
|
176
|
-
|
177
|
-
=== Wiring it all up
|
178
|
-
|
179
|
-
Just edit +lib/rscm.rb+ and +require+ your new scm class. Now you should see it coming up
|
180
|
-
on the Source Control tab in the web interface.
|
163
|
+
== Web interface (DamageControl only)
|
181
164
|
|
165
|
+
DamageControl automatically detects new SCM classes in RSCM and generates a default web interface.
|
166
|
+
|
182
167
|
= Building RSCM
|
183
168
|
This section is for developers who are new to ruby development and do not already know how to build and install Ruby gems.
|
184
169
|
|
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ require 'lib/rubyforge_file_publisher'
|
|
11
11
|
|
12
12
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
13
13
|
PKG_NAME = 'rscm'
|
14
|
-
PKG_VERSION = '0.
|
14
|
+
PKG_VERSION = '0.2.0' + PKG_BUILD
|
15
15
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
16
16
|
|
17
17
|
desc "Default Task"
|
@@ -108,28 +108,29 @@ else
|
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
|
-
task :publish do
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
"
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
p.
|
129
|
-
p.
|
130
|
-
p.
|
131
|
-
p.
|
132
|
-
p.
|
133
|
-
|
111
|
+
task :publish => [:rdoc] do
|
112
|
+
publisher = Rake::CompositePublisher.new
|
113
|
+
publisher.add Rake::RubyForgePublisher.new('rscm', 'aslak_hellesoy')
|
114
|
+
publisher.upload
|
115
|
+
|
116
|
+
# RUBYFORGE_GROUP_ID = 490
|
117
|
+
# RUBYFORGE_PACKAGE_ID = 552
|
118
|
+
# RUBYFORGE_RELEASE_NAME = "rakedrelease"
|
119
|
+
#
|
120
|
+
# Rake::RubyForgeFilePublisher.new(
|
121
|
+
# RUBYFORGE_GROUP_ID,
|
122
|
+
# "aslak_hellesoy",
|
123
|
+
# "README",
|
124
|
+
# #"pkg/#{PKG_FILE_NAME}.gem",
|
125
|
+
# RUBYFORGE_PACKAGE_ID,
|
126
|
+
# RUBYFORGE_RELEASE_NAME
|
127
|
+
# ) do |p|
|
128
|
+
# p.type_id = 8100
|
129
|
+
# p.processor_id = 2000
|
130
|
+
# p.preformatted = 1
|
131
|
+
# p.release_name = "come on"
|
132
|
+
# p.release_changes = "now"
|
133
|
+
# p.release_date = Time.utc(2005, 2, 19, 23, 42, 0)
|
134
|
+
# end
|
134
135
|
|
135
136
|
end
|
data/lib/rscm.rb
CHANGED
@@ -2,9 +2,4 @@ require 'rscm/abstract_scm'
|
|
2
2
|
require 'rscm/changes'
|
3
3
|
require 'rscm/logging'
|
4
4
|
require 'rscm/time_ext'
|
5
|
-
|
6
|
-
require 'rscm/mooky/mooky' # for demo purposes only
|
7
|
-
require 'rscm/cvs/cvs'
|
8
|
-
require 'rscm/darcs/darcs'
|
9
|
-
require 'rscm/starteam/starteam'
|
10
|
-
require 'rscm/svn/svn'
|
5
|
+
require 'rscm/abstract_scm'
|
data/lib/rscm/abstract_scm.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'rscm/changes'
|
3
3
|
require 'rscm/path_converter'
|
4
|
+
require 'rscm/annotations'
|
4
5
|
|
5
6
|
class String
|
6
7
|
# Turns a String into a Time or an int
|
@@ -40,6 +41,20 @@ module RSCM
|
|
40
41
|
class AbstractSCM
|
41
42
|
include FileUtils
|
42
43
|
|
44
|
+
@@classes = []
|
45
|
+
def self.register(cls)
|
46
|
+
@@classes << cls unless @@classes.index(cls)
|
47
|
+
end
|
48
|
+
def self.classes
|
49
|
+
@@classes
|
50
|
+
end
|
51
|
+
|
52
|
+
# Load all sources under scm, so SCM classes can register themselves
|
53
|
+
Dir[File.dirname(__FILE__) + "/scm/*.rb"].each do |src|
|
54
|
+
load(src)
|
55
|
+
end
|
56
|
+
|
57
|
+
|
43
58
|
# TODO: Make changesets yield changesets as they are determined, to avoid
|
44
59
|
# having to load them all into memory before the method exits. Careful not to
|
45
60
|
# use yielded changesets to do another scm hit - like get diffs. Some SCMs
|
@@ -62,8 +77,13 @@ module RSCM
|
|
62
77
|
false
|
63
78
|
end
|
64
79
|
|
65
|
-
# Creates a new repository.
|
66
|
-
#
|
80
|
+
# Creates a new 'central' repository. This is intended only for creation of 'central'
|
81
|
+
# repositories (not for working copies). You shouldn't have to call this method if a central repository
|
82
|
+
# already exists. This method is used primarily for testing of RSCM, but can also
|
83
|
+
# be used if you *really* want to create a central repository.
|
84
|
+
#
|
85
|
+
# This method should throw an exception if the repository cannot be created (for
|
86
|
+
# example if the repository is 'remote' or if it already exists).
|
67
87
|
#
|
68
88
|
def create
|
69
89
|
end
|
@@ -71,6 +91,7 @@ module RSCM
|
|
71
91
|
# Whether a repository can be created.
|
72
92
|
#
|
73
93
|
def can_create?
|
94
|
+
false
|
74
95
|
end
|
75
96
|
|
76
97
|
# Recursively imports files from a directory
|
@@ -96,6 +117,8 @@ module RSCM
|
|
96
117
|
end
|
97
118
|
|
98
119
|
# Checks out or updates contents from an SCM to +checkout_dir+ - a local working copy.
|
120
|
+
# If this is a distributed SCM, this method should create a 'working copy' repository
|
121
|
+
# if one doesn't already exist.
|
99
122
|
#
|
100
123
|
# The +to_identifier+ parameter may be optionally specified to obtain files up to a
|
101
124
|
# particular time or label. +time_label+ should either be a Time (in UTC - according to
|
@@ -108,13 +131,16 @@ module RSCM
|
|
108
131
|
# For some SCMs this is not possible, or at least very hard. In that case, just override
|
109
132
|
# the checkout_silent method instead of this method (should be protected).
|
110
133
|
def checkout(checkout_dir, to_identifier=Time.infinity) # :yield: file
|
111
|
-
|
134
|
+
checkout_time = Time.now
|
112
135
|
|
113
136
|
# We expect subclasses to implement this as a protected method (unless this whole method is overridden).
|
114
137
|
checkout_silent(checkout_dir, to_identifier)
|
115
138
|
|
116
|
-
|
117
|
-
added =
|
139
|
+
files = Dir["#{checkout_dir}/**/*"]
|
140
|
+
added = []
|
141
|
+
files.each do |file|
|
142
|
+
added << file if File.mtime(file) > checkout_time
|
143
|
+
end
|
118
144
|
ignore_paths.each do |regex|
|
119
145
|
added.delete_if{|path| path =~ regex}
|
120
146
|
end
|
@@ -123,7 +149,7 @@ module RSCM
|
|
123
149
|
end
|
124
150
|
relative_added_file_paths = to_relative(checkout_dir, added_file_paths)
|
125
151
|
relative_added_file_paths.each do |path|
|
126
|
-
yield path
|
152
|
+
yield path if block_given?
|
127
153
|
end
|
128
154
|
relative_added_file_paths
|
129
155
|
end
|
@@ -131,7 +157,7 @@ module RSCM
|
|
131
157
|
# Returns a ChangeSets object for the period specified by +from_identifier+
|
132
158
|
# and +to_identifier+. See AbstractSCM for details about the parameters.
|
133
159
|
#
|
134
|
-
def changesets(checkout_dir, from_identifier, to_identifier=Time.infinity
|
160
|
+
def changesets(checkout_dir, from_identifier, to_identifier=Time.infinity)
|
135
161
|
# Should be overridden by subclasses
|
136
162
|
changesets = ChangeSets.new
|
137
163
|
changesets.add(
|
@@ -149,8 +175,8 @@ module RSCM
|
|
149
175
|
changesets
|
150
176
|
end
|
151
177
|
|
152
|
-
# Whether the working copy in +checkout_dir+ is
|
153
|
-
# since +from_identifier+.
|
178
|
+
# Whether the working copy in +checkout_dir+ is in synch with the central
|
179
|
+
# repository since +from_identifier+.
|
154
180
|
#
|
155
181
|
def uptodate?(checkout_dir, from_identifier)
|
156
182
|
# Suboptimal algorithm that works for all SCMs.
|
@@ -159,7 +185,7 @@ module RSCM
|
|
159
185
|
changesets(checkout_dir, from_identifier).empty?
|
160
186
|
end
|
161
187
|
|
162
|
-
# Whether the project is checked out or not.
|
188
|
+
# Whether the project is checked out from the central repository or not.
|
163
189
|
# Subclasses should override this to check for SCM-specific administrative
|
164
190
|
# files if appliccable
|
165
191
|
def checked_out?(checkout_dir)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Class
|
2
|
+
@@anns = {}
|
3
|
+
|
4
|
+
# Defines annotation(s) for the next defined +attr_reader+ or
|
5
|
+
# +attr_accessor+. The +anns+ argument should be a Hash defining annotations
|
6
|
+
# for the associated attr. Example:
|
7
|
+
#
|
8
|
+
# require 'rscm/annotations'
|
9
|
+
#
|
10
|
+
# class EmailSender
|
11
|
+
# ann :description => "IP address of the mail server", :tip => "Use 'localhost' if you have a good box, sister!"
|
12
|
+
# attr_accessor :server
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# The EmailSender class' annotations can then be accessed like this:
|
16
|
+
#
|
17
|
+
# EmailSender.server[:description] # => "IP address of the mail server"
|
18
|
+
#
|
19
|
+
# Yeah right, cool, whatever. What's this good for? It's useful for example if you want to
|
20
|
+
# build some sort of user interface (for example in on Ruby on Rails) that allows editing of
|
21
|
+
# fields, and you want to provide an explanatory text and a tooltip in the UI.
|
22
|
+
#
|
23
|
+
# You may also use annotations to specify more programmatically meaningful metadata. More power to you.
|
24
|
+
#
|
25
|
+
def ann(anns)
|
26
|
+
$attr_anns ||= {}
|
27
|
+
$attr_anns.merge!(anns)
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(sym, *args) #:nodoc:
|
31
|
+
anns = @@anns[self]
|
32
|
+
return superclass.method_missing(sym, *args) if(anns.nil?)
|
33
|
+
anns[sym]
|
34
|
+
end
|
35
|
+
|
36
|
+
alias old_attr_reader attr_reader #:nodoc:
|
37
|
+
def attr_reader(*syms) #:nodoc:
|
38
|
+
@@anns[self] ||= {}
|
39
|
+
syms.each do |sym|
|
40
|
+
@@anns[self][sym] = $attr_anns.dup if $attr_anns
|
41
|
+
end
|
42
|
+
$attr_anns = nil
|
43
|
+
old_attr_reader(*syms)
|
44
|
+
end
|
45
|
+
|
46
|
+
def attr_accessor(*syms) #:nodoc:
|
47
|
+
attr_reader(*syms)
|
48
|
+
attr_writer(*syms)
|
49
|
+
end
|
50
|
+
end
|
data/lib/rscm/changes.rb
CHANGED
@@ -3,10 +3,7 @@ require 'rscm/time_ext'
|
|
3
3
|
|
4
4
|
module RSCM
|
5
5
|
|
6
|
-
#
|
7
|
-
# We'll be able to do lots of cool analysis with visitors later -> graphs. mmmmm.
|
8
|
-
|
9
|
-
# A collection of changesets.
|
6
|
+
# A collection of ChangeSet.
|
10
7
|
class ChangeSets
|
11
8
|
include Enumerable
|
12
9
|
include XMLRPC::Marshallable
|
@@ -220,7 +217,7 @@ module RSCM
|
|
220
217
|
# This is a UTC ruby time
|
221
218
|
attr_accessor :time
|
222
219
|
|
223
|
-
def initialize(path=nil, developer=nil, message=nil, revision=nil, time=nil
|
220
|
+
def initialize(path=nil, status=nil, developer=nil, message=nil, revision=nil, time=nil)
|
224
221
|
@path, @developer, @message, @revision, @time, @status = path, developer, message, revision, time, status
|
225
222
|
end
|
226
223
|
|
data/lib/rscm/logging.rb
CHANGED
data/lib/rscm/path_converter.rb
CHANGED
@@ -21,10 +21,11 @@ def with_working_dir(dir)
|
|
21
21
|
#
|
22
22
|
prev = Dir.pwd
|
23
23
|
begin
|
24
|
-
|
24
|
+
dir = File.expand_path(dir)
|
25
|
+
Log.info "Making directory: '#{dir}'"
|
25
26
|
FileUtils.mkdir_p(dir)
|
26
27
|
Dir.chdir(dir)
|
27
|
-
Log.info "In directory: '#{
|
28
|
+
Log.info "In directory: '#{dir}'"
|
28
29
|
yield
|
29
30
|
ensure
|
30
31
|
Dir.chdir(prev)
|
data/lib/rscm/{cvs → scm}/cvs.rb
RENAMED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rscm/abstract_scm'
|
2
2
|
require 'rscm/path_converter'
|
3
3
|
require 'rscm/line_editor'
|
4
|
-
require 'rscm/
|
4
|
+
require 'rscm/scm/cvs_log_parser'
|
5
5
|
|
6
6
|
module RSCM
|
7
7
|
|
@@ -10,12 +10,19 @@ module RSCM
|
|
10
10
|
# You need a cvs executable on the PATH in order for it to work.
|
11
11
|
#
|
12
12
|
# NOTE: On Cygwin this has to be the win32 build of cvs and not the Cygwin one.
|
13
|
-
class
|
13
|
+
class Cvs < AbstractSCM
|
14
|
+
register self
|
14
15
|
|
15
|
-
|
16
|
+
ann :description => "CVSROOT"
|
16
17
|
attr_accessor :root
|
18
|
+
|
19
|
+
ann :description => "module"
|
17
20
|
attr_accessor :mod
|
21
|
+
|
22
|
+
ann :description => "Branch"
|
18
23
|
attr_accessor :branch
|
24
|
+
|
25
|
+
ann :description => "Password", :tip => "<b>Warning!</b> Password will be shown in cleartext in configuration files."
|
19
26
|
attr_accessor :password
|
20
27
|
|
21
28
|
def initialize(root=nil, mod=nil, branch=nil, password=nil)
|
@@ -89,9 +96,9 @@ module RSCM
|
|
89
96
|
files.empty?
|
90
97
|
end
|
91
98
|
|
92
|
-
def changesets(checkout_dir, from_identifier, to_identifier=Time.infinity
|
99
|
+
def changesets(checkout_dir, from_identifier, to_identifier=Time.infinity)
|
93
100
|
checkout(checkout_dir) unless uptodate?(checkout_dir, nil) # must checkout to get changesets
|
94
|
-
parse_log(checkout_dir, changes_command(from_identifier, to_identifier
|
101
|
+
parse_log(checkout_dir, changes_command(from_identifier, to_identifier))
|
95
102
|
end
|
96
103
|
|
97
104
|
def diff(checkout_dir, change)
|
@@ -226,7 +233,7 @@ module RSCM
|
|
226
233
|
changesets = nil
|
227
234
|
with_working_dir(checkout_dir) do
|
228
235
|
safer_popen(execed_command_line) do |stdout|
|
229
|
-
parser =
|
236
|
+
parser = CvsLogParser.new(stdout)
|
230
237
|
parser.cvspath = path
|
231
238
|
parser.cvsmodule = mod
|
232
239
|
changesets = parser.parse_changesets
|
@@ -235,7 +242,7 @@ module RSCM
|
|
235
242
|
changesets
|
236
243
|
end
|
237
244
|
|
238
|
-
def changes_command(from_identifier, to_identifier
|
245
|
+
def changes_command(from_identifier, to_identifier)
|
239
246
|
# https://www.cvshome.org/docs/manual/cvs-1.11.17/cvs_16.html#SEC144
|
240
247
|
# -N => Suppress the header if no revisions are selected.
|
241
248
|
"log #{branch_option} -N #{period_option(from_identifier, to_identifier)}"
|
@@ -293,11 +300,11 @@ module RSCM
|
|
293
300
|
|
294
301
|
def command_line(cmd, password=nil, simulate=false)
|
295
302
|
cvs_options = simulate ? "-n" : ""
|
296
|
-
"cvs \"-d#{root_with_password(password)}\" #{cvs_options} -q #{cmd}"
|
303
|
+
"cvs -f \"-d#{root_with_password(password)}\" #{cvs_options} -q #{cmd}"
|
297
304
|
end
|
298
305
|
|
299
306
|
def create_root_cvs
|
300
|
-
|
307
|
+
Cvs.new(self.root, "CVSROOT", nil, self.password)
|
301
308
|
end
|
302
309
|
|
303
310
|
def revision_option(identifier)
|
@@ -5,9 +5,9 @@ require 'ftools'
|
|
5
5
|
|
6
6
|
module RSCM
|
7
7
|
|
8
|
-
class
|
9
|
-
REVISION_SEPARATOR = /^----------------------------$/
|
10
|
-
ENTRY_SEPARATOR = /^=============================================================================$/
|
8
|
+
class CvsLogParser < AbstractLogParser
|
9
|
+
REVISION_SEPARATOR = /^----------------------------$/ unless defined? REVISION_SEPARATOR
|
10
|
+
ENTRY_SEPARATOR = /^=============================================================================$/ unless defined? ENTRY_SEPARATOR
|
11
11
|
|
12
12
|
attr_accessor :cvspath
|
13
13
|
attr_accessor :cvsmodule
|
@@ -154,7 +154,7 @@ module RSCM
|
|
154
154
|
# The state field is "Exp" both for added and modified files. retards!
|
155
155
|
# We need some additional logic to figure out whether it is added or not.
|
156
156
|
# Maybe look at the revision. (1.1 means new I think. - deal with it later)
|
157
|
-
STATES = {"dead" => Change::DELETED, "Exp" => Change::MODIFIED}
|
157
|
+
STATES = {"dead" => Change::DELETED, "Exp" => Change::MODIFIED} unless defined? STATES
|
158
158
|
|
159
159
|
end
|
160
160
|
|