rscm 0.1.0.1338 → 0.2.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 +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
|
|