rscm 0.3.8 → 0.3.9
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/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
|