rscm 0.3.8 → 0.3.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +8 -0
- data/README +3 -3
- data/Rakefile +1 -1
- data/lib/rscm/base.rb +6 -0
- data/lib/rscm/scm/clearcase.rb +167 -147
- data/lib/rscm/scm/cvs.rb +5 -1
- data/lib/rscm/scm/subversion.rb +15 -17
- data/test/rscm/generic_scm_tests.rb +3 -2
- metadata +2 -2
data/CHANGES
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
= RSCM Changelog
|
2
2
|
|
3
|
+
== Version 0.3.9
|
4
|
+
|
5
|
+
This release improves Subversion and ClearCase support
|
6
|
+
|
7
|
+
* Subversion no longer needs a working copy to get revisions and diffs
|
8
|
+
* Misc. ClearCase improvements
|
9
|
+
* Added RSCM::Base.destroy_working_copy
|
10
|
+
|
3
11
|
== Version 0.3.8
|
4
12
|
|
5
13
|
Bugfix release
|
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= RSCM - Ruby Source Control Management (0.3.
|
1
|
+
= RSCM - Ruby Source Control Management (0.3.9)
|
2
2
|
|
3
3
|
RSCM is to SCM what DBI/JDBC/ODBC are to databases - an SCM-independent API for accessing different SCMs. The features are roughly:
|
4
4
|
|
@@ -31,12 +31,12 @@ If you want the latest and greatest, you can get the sources, which live alongsi
|
|
31
31
|
|
32
32
|
== Supported SCMs
|
33
33
|
|
34
|
-
* CVS - http://www.
|
34
|
+
* CVS - http://www.nongnu.org/cvs (stable)
|
35
35
|
* Subversion - http://subversion.tigris.org (stable)
|
36
|
+
* ClearCase - http://www-306.ibm.com/software/awdtools/clearcase (not thoroughly tested)
|
36
37
|
|
37
38
|
In progress:
|
38
39
|
|
39
|
-
* ClearCase -http://www-306.ibm.com/software/awdtools/clearcase (half complete)
|
40
40
|
* Darcs - http://www.abridgegame.org/darcs (very incomplete)
|
41
41
|
* Monotone - http://www.venge.net/monotone (half complete)
|
42
42
|
* Perforce - http://www.perforce.com (nearly complete - a little out of date with recent API)
|
data/Rakefile
CHANGED
data/lib/rscm/base.rb
CHANGED
@@ -21,6 +21,7 @@ module RSCM
|
|
21
21
|
# * revisions
|
22
22
|
# * uptodate?
|
23
23
|
# * file
|
24
|
+
# * destroy_working_copy
|
24
25
|
#
|
25
26
|
# In addition to operations related to working copies, the same instance should provide
|
26
27
|
# methods to administer the working copy's associated 'central' repository. These are:
|
@@ -92,6 +93,11 @@ module RSCM
|
|
92
93
|
props.sort!
|
93
94
|
end
|
94
95
|
|
96
|
+
# Destroys the working copy
|
97
|
+
def destroy_working_copy
|
98
|
+
FileUtils.rm_rf(checkout_dir) unless checkout_dir.nil?
|
99
|
+
end
|
100
|
+
|
95
101
|
# Whether the physical SCM represented by this instance exists.
|
96
102
|
#
|
97
103
|
def central_exists?
|
data/lib/rscm/scm/clearcase.rb
CHANGED
@@ -4,156 +4,176 @@ require 'fileutils'
|
|
4
4
|
require 'tempfile'
|
5
5
|
|
6
6
|
module RSCM
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
7
|
+
class ClearCase < Base
|
8
|
+
register self
|
9
|
+
|
10
|
+
LOG_FORMAT = "- !ruby/object:RSCM::RevisionFile\\n developer: %u\\n time: \\\"%Nd\\\"\\n native_revision_identifier: %Vn\\n previous_native_revision_identifier: %PVn\\n path: %En\\n status: %o\\n message: \\\"%Nc\\\"\\n\\n"
|
11
|
+
TIME_FORMAT = "%d-%b-%Y.%H:%M:%S"
|
12
|
+
MAGIC_TOKEN = "9q8w7e6r5t4y"
|
13
|
+
STATUSES = {
|
14
|
+
"checkin" => RevisionFile::MODIFIED,
|
15
|
+
"mkelem" => RevisionFile::ADDED,
|
16
|
+
"rmelem" => RevisionFile::DELETED,
|
17
|
+
}
|
18
|
+
DEFAULT_CONFIG_SPEC = "element * CHECKEDOUT\nelement * /main/LATEST"
|
19
|
+
|
20
|
+
attr_accessor :stream, :stgloc, :tag, :config_spec
|
21
|
+
|
22
|
+
def initialize(stream=nil, stgloc=nil, tag=nil, config_spec=DEFAULT_CONFIG_SPEC)
|
23
|
+
@stream, @stgloc, @tag, @config_spec = stream, stgloc, tag, config_spec
|
24
|
+
end
|
25
|
+
|
26
|
+
def revisions(from_identifier, to_identifier=Time.infinity, relative_path=nil)
|
27
|
+
checkout unless checked_out?
|
28
|
+
rules = load_rules
|
29
|
+
vob = vob(rules[0])
|
30
|
+
result = Revisions.new
|
31
|
+
|
32
|
+
unless vob
|
33
|
+
STDERR.puts "No vob found. Please set load rules in the view: #{checkout_dir}"
|
34
|
+
return result
|
35
|
+
end
|
36
|
+
with_working_dir(checkout_dir) do
|
37
|
+
since = (from_identifier + 1).strftime(TIME_FORMAT)
|
38
|
+
cmd = "cleartool lshistory -recurse -nco -since #{since} -fmt \"#{LOG_FORMAT}\" -pname #{vob}"
|
39
|
+
Better.popen(cmd) do |io|
|
40
|
+
# escape all quotes, except the one at the beginning and end. this is a bit ugly...
|
41
|
+
raw_yaml = io.read
|
42
|
+
fixed_yaml = raw_yaml.gsub(/^ message: \"/, " message: #{MAGIC_TOKEN}")
|
43
|
+
fixed_yaml = fixed_yaml.gsub(/\"\n\n/, "#{MAGIC_TOKEN}\n\n")
|
44
|
+
fixed_yaml = fixed_yaml.gsub(/\"/, "\\\"")
|
45
|
+
fixed_yaml = fixed_yaml.gsub(MAGIC_TOKEN, "\"")
|
46
|
+
|
47
|
+
files = YAML.load(fixed_yaml)
|
48
|
+
files.each do |file|
|
49
|
+
file.path.gsub!(/\\/, "/")
|
50
|
+
file.status = STATUSES[file.status]
|
51
|
+
rev = revision(file.native_revision_identifier)
|
52
|
+
if(rev && matches_load_rules?(rules, file.path))
|
53
|
+
file.native_revision_identifier = rev
|
54
|
+
file.previous_native_revision_identifier = revision(file.previous_native_revision_identifier)
|
55
|
+
t = file.time
|
56
|
+
# the time now has escaped quotes..
|
57
|
+
file.time = Time.utc(t[2..5],t[6..7],t[8..9],t[11..12],t[13..14],t[15..16])
|
58
|
+
file.message.strip!
|
59
|
+
result.add(file)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
result
|
65
|
+
end
|
66
|
+
|
67
|
+
def checked_out?
|
68
|
+
!Dir["#{checkout_dir}/*"].empty?
|
69
|
+
end
|
70
|
+
|
71
|
+
def destroy_working_copy
|
72
|
+
Better.popen("cleartool rmview #{checkout_dir}") do |io|
|
73
|
+
io.read
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def import_central(dir, message)
|
78
|
+
Better.popen("clearfsimport -recurse -nsetevent #{dir} #{checkout_dir}") do |io|
|
79
|
+
io.read
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
## Non-RSCM API methods
|
84
|
+
|
85
|
+
def mkview!
|
83
86
|
# Create view (working copy)
|
84
87
|
mkview_cmd = "cleartool mkview -snapshot -stream #{@stream} -stgloc #{@stgloc} -tag #{@tag} #{@checkout_dir}"
|
85
88
|
Better.popen(mkview_cmd) do |io|
|
86
89
|
puts io.read
|
87
90
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
91
|
+
end
|
92
|
+
|
93
|
+
def update_load_rules!
|
94
|
+
Dir.chdir(checkout_dir) do
|
95
|
+
# tempfile is broken on windows (!!)
|
96
|
+
cfg_spec_file = "__rscm.cfgspec"
|
97
|
+
config_spec_file = File.open(cfg_spec_file, "w") do |io|
|
98
|
+
io.write(@config_spec)
|
99
|
+
end
|
100
|
+
|
101
|
+
setcs_cmd = "cleartool setcs #{cfg_spec_file}"
|
102
|
+
Better.popen(setcs_cmd, "w") do |io|
|
103
|
+
io.write "yes\n"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def catcs
|
109
|
+
Dir.chdir(checkout_dir) do
|
110
|
+
catcs_cmd = "cleartool catcs"
|
111
|
+
Better.popen(catcs_cmd) do |io|
|
112
|
+
yield io
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def vob(load_rule)
|
118
|
+
if(load_rule =~ /[\\\/]*([\w]*)/)
|
119
|
+
$1
|
120
|
+
else
|
121
|
+
nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# What's loaded into view
|
126
|
+
def load_rules
|
127
|
+
result = []
|
128
|
+
catcs do |io|
|
129
|
+
io.each_line do |line|
|
130
|
+
if(line =~ /^load[\s]*(.*)$/)
|
131
|
+
return result << $1
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
result
|
136
|
+
end
|
137
|
+
|
138
|
+
protected
|
139
|
+
|
140
|
+
def checkout_silent(to_identifier=nil)
|
141
|
+
if(checked_out?)
|
142
|
+
with_working_dir(checkout_dir) do
|
143
|
+
Better.popen("cleartool update .") do |io|
|
144
|
+
io.read
|
145
|
+
end
|
146
|
+
end
|
147
|
+
else
|
148
|
+
mkview!
|
149
|
+
|
150
|
+
# Set load rules (by setting config spec)
|
151
|
+
#update_load_rules!
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Administrative files that should be ignored when counting files.
|
156
|
+
def ignore_paths
|
157
|
+
return [/.*\.updt/]
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def revision(s)
|
163
|
+
if(s =~ /.*\\([\d]*)/)
|
164
|
+
$1.to_i
|
165
|
+
else
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def matches_load_rules?(rules, path)
|
171
|
+
rules.each do |rule|
|
172
|
+
rule.gsub!(/\\/, "/")
|
173
|
+
return true if path =~ /#{rule[1..-1]}/
|
174
|
+
end
|
175
|
+
false
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
159
179
|
end
|
data/lib/rscm/scm/cvs.rb
CHANGED
@@ -190,7 +190,11 @@ module RSCM
|
|
190
190
|
end
|
191
191
|
|
192
192
|
def destroy_central
|
193
|
-
|
193
|
+
if(File.exist?(path) && local?)
|
194
|
+
FileUtils.rm_rf(path)
|
195
|
+
else
|
196
|
+
raise "Cannot destroy central repository. '#{path}' doesn't exist or central repo isn't local to this machine"
|
197
|
+
end
|
194
198
|
end
|
195
199
|
|
196
200
|
def central_exists?
|
data/lib/rscm/scm/subversion.rb
CHANGED
@@ -107,11 +107,9 @@ module RSCM
|
|
107
107
|
end
|
108
108
|
|
109
109
|
def diff(file, &block)
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
return(yield(io))
|
114
|
-
end
|
110
|
+
cmd = "svn diff --revision #{file.previous_native_revision_identifier}:#{file.native_revision_identifier} \"#{url}/#{file.path}\""
|
111
|
+
Better.popen(cmd) do |io|
|
112
|
+
return(yield(io))
|
115
113
|
end
|
116
114
|
end
|
117
115
|
|
@@ -126,7 +124,11 @@ module RSCM
|
|
126
124
|
end
|
127
125
|
|
128
126
|
def destroy_central
|
129
|
-
|
127
|
+
if(File.exist?(svnrootdir) && local?)
|
128
|
+
FileUtils.rm_rf(svnrootdir)
|
129
|
+
else
|
130
|
+
raise "Cannot destroy central repository. '#{svnrootdir}' doesn't exist or central repo isn't local to this machine"
|
131
|
+
end
|
130
132
|
end
|
131
133
|
|
132
134
|
def central_exists?
|
@@ -200,11 +202,9 @@ module RSCM
|
|
200
202
|
revisions = nil
|
201
203
|
command = "svn #{changes_command(from_identifier, to_identifier, relative_path)}"
|
202
204
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
revisions = parser.parse_revisions
|
207
|
-
end
|
205
|
+
Better.popen(command) do |stdout|
|
206
|
+
parser = SubversionLogParser.new(stdout, @url)
|
207
|
+
revisions = parser.parse_revisions
|
208
208
|
end
|
209
209
|
revisions
|
210
210
|
end
|
@@ -238,12 +238,10 @@ module RSCM
|
|
238
238
|
# We therefore don't specify it and get the latest revision from the full url instead.
|
239
239
|
# cmd = "svn log #{login_options} #{repourl} -r HEAD"
|
240
240
|
cmd = "svn log #{login_options} #{url}"
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
revisions[0].identifier.to_i
|
246
|
-
end
|
241
|
+
Better.popen(cmd) do |stdout|
|
242
|
+
parser = SubversionLogParser.new(stdout, @url)
|
243
|
+
revisions = parser.parse_revisions
|
244
|
+
revisions[0].identifier.to_i
|
247
245
|
end
|
248
246
|
end
|
249
247
|
|
@@ -11,10 +11,11 @@ module RSCM
|
|
11
11
|
def teardown
|
12
12
|
if @scm
|
13
13
|
begin
|
14
|
-
@scm.
|
14
|
+
@scm.destroy_working_copy
|
15
|
+
@scm.destroy_central
|
15
16
|
rescue => e
|
16
17
|
# Fails on windows with TortoiseCVS' cvs because of resident cvslock.exe
|
17
|
-
STDERR.puts "Couldn't destroy central #{@scm.class.name}"
|
18
|
+
STDERR.puts "Couldn't destroy central #{@scm.class.name}: #{e.message}"
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: rscm
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.3.
|
7
|
-
date: 2005-10-
|
6
|
+
version: 0.3.9
|
7
|
+
date: 2005-10-12 00:00:00 -04:00
|
8
8
|
summary: "RSCM - Ruby Source Control Management"
|
9
9
|
require_paths:
|
10
10
|
- lib
|