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 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.8)
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.cvshome.org (stable)
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
@@ -10,7 +10,7 @@ require 'meta_project'
10
10
 
11
11
  PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
12
12
  PKG_NAME = 'rscm'
13
- PKG_VERSION = '0.3.8' + PKG_BUILD
13
+ PKG_VERSION = '0.3.9' + PKG_BUILD
14
14
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
15
15
 
16
16
  desc "Default Task"
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?
@@ -4,156 +4,176 @@ require 'fileutils'
4
4
  require 'tempfile'
5
5
 
6
6
  module RSCM
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 = "9q8w7e6r5t4y"
13
- STATUSES = {
14
- "checkin" => RevisionFile::MODIFIED,
15
- "mkelem" => RevisionFile::ADDED,
16
- "rmelem" => RevisionFile::DELETED,
17
- }
18
-
19
- attr_accessor :stream, :stgloc, :tag, :config_spec
20
-
21
- def initialize(stream=nil, stgloc=nil, tag=nil, config_spec=nil)
22
- @stream, @stgloc, @tag, @config_spec = stream, stgloc, tag, config_spec
23
- end
24
-
25
- def revisions(from_identifier, to_identifier=Time.infinity, relative_path=nil)
26
- checkout unless checked_out?
27
-
28
- rules = load_rules
29
- vob = vob(rules[0])
30
-
31
- result = Revisions.new
32
- with_working_dir(checkout_dir) do
33
- since = (from_identifier + 1).strftime(TIME_FORMAT)
34
- cmd = "cleartool lshistory -recurse -nco -since #{since} -fmt \"#{LOG_FORMAT}\" -pname #{vob}"
35
- Better.popen(cmd) do |io|
36
- # escape all quotes, except the one at the beginning and end. this is a bit ugly...
37
- raw_yaml = io.read
38
- fixed_yaml = raw_yaml.gsub(/^ message: \"/, " message: #{MAGIC}")
39
- fixed_yaml = fixed_yaml.gsub(/\"\n\n/, "#{MAGIC}\n\n")
40
- fixed_yaml = fixed_yaml.gsub(/\"/, "\\\"")
41
- fixed_yaml = fixed_yaml.gsub(MAGIC, "\"")
42
-
43
- files = YAML.load(fixed_yaml)
44
- files.each do |file|
45
- file.path.gsub!(/\\/, "/")
46
- file.status = STATUSES[file.status]
47
- rev = revision(file.native_revision_identifier)
48
- if(rev && matches_load_rules?(rules, file.path))
49
- file.native_revision_identifier = rev
50
- file.previous_native_revision_identifier = revision(file.previous_native_revision_identifier)
51
- t = file.time
52
- # the time now has escaped quotes..
53
- file.time = Time.utc(t[2..5],t[6..7],t[8..9],t[11..12],t[13..14],t[15..16])
54
- file.message.strip!
55
- result.add(file)
56
- end
57
- end
58
- end
59
- end
60
- result
61
- end
62
-
63
- def checked_out?
64
- File.exist?(checkout_dir)
65
- end
66
-
67
- def destroy_working_copy
68
- Better.popen("cleartool rmview #{checkout_dir}") do |io|
69
- io.read
70
- end
71
- end
72
-
73
- protected
74
-
75
- def checkout_silent(to_identifier=nil)
76
- if(checked_out?)
77
- with_working_dir(checkout_dir) do
78
- Better.popen("cleartool update .") do |io|
79
- io.read
80
- end
81
- end
82
- else
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
- # Set load rules (by setting config spec)
90
- Dir.chdir(checkout_dir) do
91
- # tempfile is broken on windows (!!)
92
- cfg_spec_file = "__rscm.cfgspec"
93
- config_spec_file = File.open(cfg_spec_file, "w") do |io|
94
- io.write(@config_spec)
95
- end
96
-
97
- setcs_cmd = "cleartool setcs #{cfg_spec_file}"
98
- Better.popen(setcs_cmd, "w") do |io|
99
- io.write "yes\n"
100
- end
101
- end
102
- end
103
- end
104
-
105
- # Administrative files that should be ignored when counting files.
106
- def ignore_paths
107
- return [/.*\.updt/]
108
- end
109
-
110
- private
111
-
112
- def vob(rule)
113
- if(rule =~ /[\\\/]*([\w]*)/)
114
- $1
115
- else
116
- nil
117
- end
118
- end
119
-
120
- # What's loaded into view
121
- def load_rules
122
- result = []
123
- config_spec do |io|
124
- io.each_line do |line|
125
- if(line =~ /^load[\s]*(.*)$/)
126
- return result << $1
127
- end
128
- end
129
- end
130
- result
131
- end
132
-
133
- def config_spec
134
- Dir.chdir(checkout_dir) do
135
- catcs_cmd = "cleartool catcs"
136
- Better.popen(catcs_cmd) do |io|
137
- yield io
138
- end
139
- end
140
- end
141
-
142
- def revision(s)
143
- if(s =~ /.*\\([\d]*)/)
144
- $1.to_i
145
- else
146
- nil
147
- end
148
- end
149
-
150
- def matches_load_rules?(rules, path)
151
- rules.each do |rule|
152
- rule.gsub!(/\\/, "/")
153
- return true if path =~ /#{rule[1..-1]}/
154
- end
155
- false
156
- end
157
-
158
- end
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
- FileUtils.rm_rf(path)
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?
@@ -107,11 +107,9 @@ module RSCM
107
107
  end
108
108
 
109
109
  def diff(file, &block)
110
- with_working_dir(@checkout_dir) do
111
- cmd = "svn diff --revision #{file.previous_native_revision_identifier}:#{file.native_revision_identifier} \"#{url}/#{file.path}\""
112
- Better.popen(cmd) do |io|
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
- FileUtils.rm_rf(svnrootdir)
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
- with_working_dir(@checkout_dir) do
204
- Better.popen(command) do |stdout|
205
- parser = SubversionLogParser.new(stdout, @url)
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
- with_working_dir(@checkout_dir) do
242
- Better.popen(cmd) do |stdout|
243
- parser = SubversionLogParser.new(stdout, @url)
244
- revisions = parser.parse_revisions
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.destroy_centra
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.8
7
- date: 2005-10-11 00:00:00 -04:00
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