rscm 0.4.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +15 -0
- data/README +91 -81
- data/Rakefile +5 -1
- data/lib/rscm/base.rb +20 -27
- data/lib/rscm/command_line.rb +2 -2
- data/lib/rscm/difftool.rb +19 -8
- data/lib/rscm/revision.rb +14 -1
- data/lib/rscm/revision_file.rb +10 -0
- data/lib/rscm/scm/cvs.rb +3 -3
- data/lib/rscm/scm/mooky.rb +0 -6
- data/lib/rscm/scm/perforce.rb +112 -451
- data/lib/rscm/tempdir.rb +5 -0
- data/lib/rscm/version.rb +1 -1
- data/test/rscm/compatibility/config.yml +4 -0
- data/test/rscm/compatibility/cvs_metaproject/files_0.yml +13 -0
- data/test/rscm/compatibility/cvs_metaproject/revisions.yml +129 -0
- data/test/rscm/compatibility/cvs_metaproject/scm.yml +3 -0
- data/test/rscm/compatibility/damage_control_minimal.rb +104 -0
- data/test/rscm/{generic_scm_tests.rb → compatibility/full.rb} +8 -15
- data/test/rscm/compatibility/subversion_rscm/files_0.yml +35 -0
- data/test/rscm/compatibility/subversion_rscm/revisions.yml +69 -0
- data/test/rscm/compatibility/subversion_rscm/scm.yml +2 -0
- data/test/rscm/compatibility/subversion_rscm/svn_log_bug_irc.txt +87 -0
- data/test/rscm/scm/cvs_log_parser_test.rb +1 -0
- data/test/rscm/scm/cvs_test.rb +9 -15
- data/test/rscm/scm/mooky_test.rb +2 -9
- data/test/rscm/scm/perforce_test.rb +2 -31
- data/test/rscm/scm/subversion_test.rb +3 -6
- data/test/rscm/test_helper.rb +9 -0
- metadata +16 -4
- data/lib/rscm/scm/subversion_log_parser.rb.rej +0 -39
data/CHANGES
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
= RSCM Changelog
|
2
2
|
|
3
|
+
== 0.4.4
|
4
|
+
This release introduces a new test suite that makes it a LOT easier to implement
|
5
|
+
new RSCM adapters. The main difference is that implementations no longer have to
|
6
|
+
implement the entire API. There are two test suites - one for the full API, and
|
7
|
+
one for DamageControl (which is only a small subset of the full API).
|
8
|
+
|
9
|
+
New RSCM adapters can be written only to pass the DamageControl compatibility suite,
|
10
|
+
which requires a much smaller effort than implementing the full API. The DamageControl
|
11
|
+
compatibility suite assumes there is an existing repository somewhere, and none of
|
12
|
+
the API methods that modify repository state need to be implemented.
|
13
|
+
|
14
|
+
* Added damagecontrol compatibility suite
|
15
|
+
* RSCM::Base.default_options now defaults to {}
|
16
|
+
* Fixed bug that would cause a bad commandline when stdout is not specified and a block is passed.
|
17
|
+
|
3
18
|
== 0.4.3
|
4
19
|
|
5
20
|
This release fixes a subtle bug in revision detection for Subversion
|
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= RSCM - Ruby Source Control Management (0.4.
|
1
|
+
= RSCM - Ruby Source Control Management (0.4.4)
|
2
2
|
|
3
3
|
RSCM is to SCM what DBI/JDBC/ODBC are to databases - an SCM-independent API for accessing different SCMs. The high level features are roughly:
|
4
4
|
|
@@ -18,14 +18,12 @@ RSCM is available as a RubyGem, and can be installed like this:
|
|
18
18
|
|
19
19
|
gem install rscm
|
20
20
|
|
21
|
-
(You may need administrator access to do this on a POSIX system).
|
22
|
-
|
21
|
+
(You may need administrator access to do this on a POSIX system). You can also download prebuilt gems from
|
22
|
+
http://rubyforge.org/frs/?group_id=490
|
23
23
|
|
24
|
-
|
25
|
-
svn co svn://svn.damagecontrol.codehaus.org/damagecontrol/scm/trunk/rscm
|
24
|
+
If you want the latest and greatest, you can get the sources from subversion:
|
26
25
|
|
27
|
-
|
28
|
-
svn co svn+ssh://developer@beaver.codehaus.org/home/projects/damagecontrol/scm/trunk/rscm
|
26
|
+
svn co svn://buildpatterns.com/svn/repos/rscm/trunk
|
29
27
|
|
30
28
|
== Contributors
|
31
29
|
|
@@ -53,8 +51,8 @@ Loads! All of them! How to add support for a new one is described further down i
|
|
53
51
|
|
54
52
|
== Related projects
|
55
53
|
|
56
|
-
* DamageControl - http://
|
57
|
-
built
|
54
|
+
* DamageControl - http://dev.buildpatterns.com/trac/wiki/DamageControl (Continuous Integration system
|
55
|
+
built on top of RSCM and Ruby on Rails).
|
58
56
|
|
59
57
|
== Sample usage
|
60
58
|
|
@@ -63,28 +61,15 @@ Here is an example of how to use RSCM to get a list of revisions (aka changesets
|
|
63
61
|
require 'rscm'
|
64
62
|
|
65
63
|
scm = RSCM::Subversion.new("svn://some.server/some/path/trunk")
|
66
|
-
scm.default_options = {:stdout => "stdout.log", :stderr => "stderr.log"}
|
67
64
|
# What follows would look the same for any supported SCM
|
68
65
|
revisions = scm.revisions(Time.utc(2004, 11, 10, 12, 34, 22)) # For Subversion, you can also pass a revision number (int)
|
69
66
|
revisions.each do |revision|
|
70
67
|
puts revision # or do something more funky with it
|
71
68
|
end
|
72
69
|
|
73
|
-
=== Using visitors
|
74
|
-
|
75
|
-
Although the Revisions and Revision classes support external iteration
|
76
|
-
(with +each+ as in the example above), they also support
|
77
|
-
visitor traversal via their +accept+ methods. A visitor
|
78
|
-
must respond to the following methods:
|
79
|
-
|
80
|
-
def visit_revisions(revisions); end
|
81
|
-
def visit_revision(revision); end
|
82
|
-
def visit_file(revision_file); end
|
83
|
-
|
84
70
|
== Future plans
|
85
71
|
|
86
72
|
=== Cross-SCM synchronisation
|
87
|
-
|
88
73
|
RSCM could be used as a tool to migrate files from one SCM to another (of a different type)
|
89
74
|
while keeping the history. -Similar to cvs2svn or http://nautilus.homeip.net/~lele/projects/tailor/
|
90
75
|
|
@@ -92,88 +77,113 @@ RSCM could also be used as a continuous synchronisation service between SCMs. Th
|
|
92
77
|
when you have to work with an SCM and you'd rather use a different one. RSCM could synchronise between
|
93
78
|
the central SCM and one that you set up on your local machine.
|
94
79
|
|
95
|
-
|
80
|
+
=== SCM browser
|
81
|
+
A rails webapp that allows browsing of a repository, using RSCM to access it. -Perhaps even with a simple
|
82
|
+
editor allowing people to modify files and commit them via the browser.
|
96
83
|
|
97
|
-
|
98
|
-
file a JIRA issue (http://jira.codehaus.org/browse/DC) and hope for someone to implement it for you, or
|
99
|
-
you can do it yourself. The rest of this file should get you started.
|
84
|
+
= Implementing a new RSCM adapter
|
100
85
|
|
101
|
-
|
102
|
-
|
103
|
-
|
86
|
+
If you want RSCM to support a new SCM, you must implement a subclass of RSCM::Base.
|
87
|
+
You should focus on implementing only the features that you need. For example, if
|
88
|
+
you plan to use your new RSCM adapter with DamageControl, you only need to implement
|
89
|
+
the parts of the API that are used by DamageControl.
|
104
90
|
|
105
|
-
|
106
|
-
|
91
|
+
We'll see what steps are needed to make an adapter that passes the DamageControl compatibility suite
|
92
|
+
(which is part of RSCM). Let's imagine we want DamageControl to be able to work with the imaginary SCM
|
93
|
+
called Mooky. The rest of this section explains how to get started. You're going to need a preexisting
|
94
|
+
repository with some existing contents, basic knowledge of the SCM's command line tools and some Ruby
|
95
|
+
programming skills.
|
107
96
|
|
108
|
-
==
|
97
|
+
== Create the test class and the implementation class
|
109
98
|
|
110
|
-
Start by writing a test:
|
99
|
+
Start by writing a test that includes the compatibility test suite you're interested in:
|
111
100
|
|
112
|
-
test/rscm/
|
101
|
+
test/rscm/scm/mooky_test.rb
|
113
102
|
|
114
|
-
|
115
|
-
acceptance test suite for RSCM. By doing this you'll actually follow a TDD
|
116
|
-
approach for your new Mooky class - except that the tests are already written
|
117
|
-
for you!
|
103
|
+
With the following content:
|
118
104
|
|
119
|
-
|
120
|
-
(such as with StarTeam) you're probably better off writing the tests from scratch and not
|
121
|
-
include GenericSCMTests. Instead, just make sure you have an SCM repository set up somewhere
|
122
|
-
and write tests to work against that repository. This way you won't be able to pass the
|
123
|
-
generic acceptance test suite, and other people (like the RSCM dev team) will probably
|
124
|
-
not be able to run the tests for it. -But it's better than nothing. We'll happily accept
|
125
|
-
contributions that don't use the generic tests, although it would be best if they did.
|
105
|
+
require 'rscm/test_helper'
|
126
106
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
107
|
+
module RSCM
|
108
|
+
class MookyTest < Test::Unit::TestCase
|
109
|
+
include Compatibility::DamageControlMinimal
|
110
|
+
end
|
111
|
+
end
|
132
112
|
|
133
|
-
|
113
|
+
Now create the implementation class:
|
134
114
|
|
135
115
|
lib/rscm/scm/mooky.rb
|
136
116
|
|
137
|
-
|
117
|
+
With the following content:
|
118
|
+
|
119
|
+
require 'rscm/base'
|
120
|
+
|
121
|
+
module RSCM
|
122
|
+
class Cvs < Base
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
Now that we have set up the basics, we can run the tests:
|
138
127
|
|
139
128
|
rake test TEST=test/rscm/scm/mooky_test.rb
|
140
|
-
|
141
|
-
Whoops - we got some failures! It failed because our checkout method returned
|
142
|
-
nothing (nil). Let'see if we can get the a little further by implementing this
|
143
|
-
method.
|
144
129
|
|
145
|
-
|
146
|
-
From the command line a checkout with mooky would be done like this:
|
130
|
+
It will fail - there is still some setup to do:
|
147
131
|
|
148
|
-
|
149
|
-
|
132
|
+
== Create testdata directory
|
133
|
+
You must create a new directory under test/rscm/compatibility to contain testdata. Give it a name representative
|
134
|
+
of the scm type and the contents of the scm. For example, if the existing mooky repository we're going to test
|
135
|
+
against contains source code for a chess engine, we could call the directory test/rscm/compatibility/mooky_chess.
|
150
136
|
|
151
|
-
|
137
|
+
Also add an entry in test/rscm/compatibility/config.yml mapping your test class to the testdata directory.
|
152
138
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
should
|
139
|
+
The DamageControl compatibility suite expects to find three YAML files in this directory, scm.yml, revisions.yml
|
140
|
+
and files_0.yml.
|
141
|
+
|
142
|
+
=== Create scm.yml
|
143
|
+
This file should contain a YAML representation of the SCM instance used for testing. The test suite will load it to create an instance of your class. You're free to use whatever properties you want in your SCM implementation, and the YAML file should
|
144
|
+
contain the necessary values to connect to the preexisting repository.
|
145
|
+
|
146
|
+
=== Create revisions.yml
|
147
|
+
This file should contain a RSCM::Revisions object with two RSCM::Revision objects. You can start off by making a copy of one of the
|
148
|
+
existing revisions.yml files, but you should hand-edit this file to represent two revisions in the existing repository.
|
149
|
+
|
150
|
+
You cannot choose any revision though. There are some constraints that need to be followed:
|
151
|
+
* There must be exactly two RSCM::Revision objects
|
152
|
+
* The two RSCM::Revision objects must represent to adjacent revisions from the repository
|
153
|
+
* Each of the RSCM::Revision objects must contain at least two RSCM::RevisionFile objects
|
154
|
+
* The second RSCM::Revision object must contain at least one RSCM::RevisionFile with "ADDED" state
|
155
|
+
|
156
|
+
Given these constraints you should spend some time locating two revisions that follow these constraints.
|
157
|
+
This would be a good time to familiarize yourself with the SCM's command line tool (or whatever kind of tool
|
158
|
+
the SCM provides to access it).
|
162
159
|
|
163
|
-
|
164
|
-
on going until all tests pass.
|
160
|
+
==== Special note for non-transactional SCMs
|
165
161
|
|
166
|
-
|
167
|
-
|
168
|
-
|
162
|
+
Non-transactional SCMs usually use dates (and not revision identifiers) to report changes. Most SCMs report changes to files
|
163
|
+
(which will become RSCM::RevisionFile instances) in some sort of log. These changes will typically not be logically
|
164
|
+
grouped. RSCM::Revisions.add will group revision files that have:
|
165
|
+
* similar modification time (max 1 minute apart)
|
166
|
+
* the same commit message
|
167
|
+
* the same developer
|
169
168
|
|
170
|
-
|
171
|
-
|
172
|
-
|
169
|
+
So when mining for revisions that follow the constraints for revisions.yml, you should also be looking for groupings
|
170
|
+
in modification time, commit message and developer.
|
171
|
+
|
172
|
+
=== Create files_0.yml
|
173
|
+
This file should contain the files that will be in the working copy after a checkout of the 1st revision in revisions.yml,
|
174
|
+
sorted by their path.
|
175
|
+
|
176
|
+
== Implement the methods
|
177
|
+
Now that we have set up everything needed for the tests, we can run the tests again:
|
178
|
+
|
179
|
+
rake test TEST=test/rscm/scm/mooky_test.rb
|
173
180
|
|
174
|
-
|
181
|
+
Now you should get errors about methods not being implemented. At this point you should start implementing the methods.
|
175
182
|
|
176
|
-
|
183
|
+
== Implementation tips
|
184
|
+
* Run the tests often. Let the error messages guide you in what you do next.
|
185
|
+
* Use the execute method to invoke command line tools.
|
186
|
+
* Split the implementation into two classes. One class for parsing logs and one for translating API calls to command line executions. This will allow you to test the log parsing against hard coded logs in your tests.
|
177
187
|
|
178
188
|
= Building RSCM
|
179
189
|
This section is for developers who are new to ruby development and do not already know how to build and install Ruby gems.
|
@@ -189,6 +199,6 @@ Now change to the RSCM root directory and type
|
|
189
199
|
|
190
200
|
This will create a gem for RSCM. To install this gem, you have to change to the pkg directory and type
|
191
201
|
|
192
|
-
sudo gem install pkg/rscm-0.
|
202
|
+
sudo gem install pkg/rscm-0.4.X.gem
|
193
203
|
|
194
204
|
Now you can use RSCM in other Ruby apps with a simple require 'rscm'.
|
data/Rakefile
CHANGED
@@ -6,7 +6,6 @@ require 'rake/packagetask'
|
|
6
6
|
require 'rake/gempackagetask'
|
7
7
|
require 'rake/contrib/sshpublisher'
|
8
8
|
require 'rake/contrib/rubyforgepublisher'
|
9
|
-
require 'meta_project'
|
10
9
|
require 'lib/rscm/version'
|
11
10
|
|
12
11
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
@@ -26,6 +25,8 @@ fl.exclude('test/**/mooky*.rb')
|
|
26
25
|
fl.exclude('test/**/monotone*.rb') # Incomplete/unsupported for now - reactivate when more complete!
|
27
26
|
fl.exclude('test/**/clearcase*.rb') # Incomplete/unsupported for now - reactivate when more complete!
|
28
27
|
fl.exclude('test/**/darcs*.rb') # Incomplete/unsupported for now - reactivate when more complete!
|
28
|
+
#fl.exclude('test/**/cvs*.rb') # Incomplete/unsupported for now - reactivate when more complete!
|
29
|
+
#fl.exclude('test/**/subversion*.rb') # Incomplete/unsupported for now - reactivate when more complete!
|
29
30
|
fl.exclude('test/**/perforce*.rb') # Incomplete/unsupported for now - reactivate when more complete!
|
30
31
|
fl.exclude('test/**/p4client*.rb') # Incomplete/unsupported for now - reactivate when more complete!
|
31
32
|
fl.exclude('test/**/starteam*.rb') # Too bloody hard to test without a StarTeam server license! Tested ad-hoc.
|
@@ -124,6 +125,7 @@ end
|
|
124
125
|
|
125
126
|
desc "Release files on RubyForge"
|
126
127
|
task :release_files => [:gem] do
|
128
|
+
require 'meta_project'
|
127
129
|
release_files = FileList[
|
128
130
|
"pkg/#{PKG_FILE_NAME}.gem"
|
129
131
|
]
|
@@ -140,12 +142,14 @@ end
|
|
140
142
|
|
141
143
|
desc "Publish docs/website"
|
142
144
|
task :publish_doc => [:rdoc] do
|
145
|
+
require 'meta_project'
|
143
146
|
publisher = Rake::RubyForgePublisher.new(PKG_NAME, ENV['RUBYFORGE_USER'])
|
144
147
|
publisher.upload
|
145
148
|
end
|
146
149
|
|
147
150
|
desc "Publish news on RubyForge"
|
148
151
|
task :publish_news => [:gem] do
|
152
|
+
require 'meta_project'
|
149
153
|
release_files = FileList[
|
150
154
|
"pkg/#{PKG_FILE_NAME}.gem"
|
151
155
|
]
|
data/lib/rscm/base.rb
CHANGED
@@ -28,7 +28,10 @@ module RSCM
|
|
28
28
|
#
|
29
29
|
class Base
|
30
30
|
|
31
|
-
|
31
|
+
attr_writer :default_options
|
32
|
+
def default_options
|
33
|
+
@default_options ||= {:stdout=>'stdout.log', :stderr=>'stderr.log'}
|
34
|
+
end
|
32
35
|
|
33
36
|
# Transforms +raw_identifier+ into the native rype used for revisions.
|
34
37
|
def to_identifier(raw_identifier)
|
@@ -54,12 +57,12 @@ module RSCM
|
|
54
57
|
end
|
55
58
|
|
56
59
|
# Destroys the working copy
|
57
|
-
def destroy_working_copy
|
60
|
+
def destroy_working_copy
|
58
61
|
FileUtils.rm_rf(checkout_dir) unless checkout_dir.nil?
|
59
62
|
end
|
60
63
|
|
61
64
|
# Whether or not the SCM represented by this instance exists.
|
62
|
-
def central_exists?
|
65
|
+
def central_exists?
|
63
66
|
# The default implementation assumes yes - override if it can be
|
64
67
|
# determined programmatically.
|
65
68
|
true
|
@@ -139,30 +142,28 @@ module RSCM
|
|
139
142
|
# the checkout_silent method instead of this method (should be protected).
|
140
143
|
#
|
141
144
|
def checkout(to_identifier=Time.infinity, options={}) # :yield: file
|
142
|
-
to_identifier=Time.infinity if to_identifier.nil?
|
143
|
-
|
144
|
-
# the OS doesn't store file timestamps with fractions.
|
145
|
-
before_checkout_time = Time.now.utc - 1
|
145
|
+
to_identifier = Time.infinity if to_identifier.nil?
|
146
146
|
|
147
|
+
before = checked_out_files
|
147
148
|
# We expect subclasses to implement this as a protected method (unless this whole method is overridden).
|
148
149
|
checkout_silent(to_identifier, options)
|
150
|
+
after = checked_out_files
|
151
|
+
|
152
|
+
(after - before).sort!
|
153
|
+
end
|
154
|
+
|
155
|
+
def checked_out_files
|
149
156
|
files = Dir["#{@checkout_dir}/**/*"]
|
150
|
-
|
151
|
-
files.each do |file|
|
152
|
-
added << file if File.mtime(file).utc > before_checkout_time
|
153
|
-
end
|
157
|
+
files.delete_if{|file| File.directory?(file)}
|
154
158
|
ignore_paths.each do |regex|
|
155
|
-
|
159
|
+
files.delete_if{|file| file =~ regex}
|
156
160
|
end
|
157
|
-
|
158
|
-
|
159
|
-
end
|
160
|
-
relative_added_file_paths = to_relative(checkout_dir, added_file_paths)
|
161
|
-
relative_added_file_paths
|
161
|
+
dir = File.expand_path(@checkout_dir)
|
162
|
+
files.collect{|file| File.expand_path(file)[dir.length+1..-1]}
|
162
163
|
end
|
163
164
|
|
164
|
-
# Returns a Revisions object for the
|
165
|
-
# and
|
165
|
+
# Returns a Revisions object for the interval specified by +from_identifier+ (exclusive, i.e. after)
|
166
|
+
# and optionally +:to_identifier+ (inclusive). If +relative_path+ is specified, the result will only contain
|
166
167
|
# revisions pertaining to that path.
|
167
168
|
#
|
168
169
|
def revisions(from_identifier, options={})
|
@@ -276,13 +277,5 @@ module RSCM
|
|
276
277
|
end
|
277
278
|
end
|
278
279
|
|
279
|
-
# Takes an array of +absolute_paths+ and turns it into an array
|
280
|
-
# of paths relative to +dir+
|
281
|
-
#
|
282
|
-
def to_relative(dir, absolute_paths)
|
283
|
-
dir = File.expand_path(dir)
|
284
|
-
absolute_paths.collect{|p| File.expand_path(p)[dir.length+1..-1]}
|
285
|
-
end
|
286
|
-
|
287
280
|
end
|
288
281
|
end
|
data/lib/rscm/command_line.rb
CHANGED
@@ -64,7 +64,7 @@ module RSCM
|
|
64
64
|
Dir.chdir(options[:dir]) do
|
65
65
|
stdout_opt = options[:stdout] ? ">> #{options[:stdout]}" : ""
|
66
66
|
stderr_opt = options[:stderr] ? "2>> #{options[:stderr]}" : ""
|
67
|
-
capture_info_command = block_given? ? "echo [output captured and therefore not logged] >> #{options[:stdout]} && " : ""
|
67
|
+
capture_info_command = (block_given? && options[:stdout])? "echo [output captured and therefore not logged] >> #{options[:stdout]} && " : ""
|
68
68
|
|
69
69
|
full_cmd = commands.collect do |c|
|
70
70
|
escaped_command = c.gsub(/"/, "\\\"").gsub(/</, "\\<")
|
@@ -93,7 +93,7 @@ module RSCM
|
|
93
93
|
if options[:stderr] && File.exist?(options[:stderr])
|
94
94
|
File.open(options[:stderr]) do |errio|
|
95
95
|
begin
|
96
|
-
errio.seek(-
|
96
|
+
errio.seek(-1200, IO::SEEK_END)
|
97
97
|
rescue Errno::EINVAL
|
98
98
|
# ignore - it just means we didn't have 400 bytes.
|
99
99
|
end
|
data/lib/rscm/difftool.rb
CHANGED
@@ -6,25 +6,36 @@ module RSCM
|
|
6
6
|
module Difftool
|
7
7
|
# assertion method that reports differences as diff.
|
8
8
|
# useful when comparing big strings
|
9
|
-
def assert_equal_with_diff(expected, actual, temp_basedir=File.dirname(__FILE__) + "/../../target")
|
10
|
-
diff(expected, actual, temp_basedir) do |diff_io|
|
9
|
+
def assert_equal_with_diff(expected, actual, message="", temp_basedir=File.dirname(__FILE__) + "/../../target")
|
10
|
+
diff(expected, actual, temp_basedir) do |diff_io, cmd|
|
11
11
|
diff_string = diff_io.read
|
12
|
-
|
12
|
+
if(diff_string.strip != "")
|
13
|
+
flunk "#{message}\nThere were differences\ndiff command: #{cmd}\ndiff:\n#{diff_string}"
|
14
|
+
end
|
13
15
|
end
|
14
16
|
end
|
15
17
|
module_function :assert_equal_with_diff
|
16
18
|
|
17
19
|
def diff(expected, actual, temp_basedir, &block)
|
18
20
|
dir = RSCM.new_temp_dir("diff", temp_basedir)
|
19
|
-
|
20
|
-
expected_file =
|
21
|
+
|
22
|
+
expected_file = nil
|
23
|
+
if(File.exist?(expected))
|
24
|
+
expected_file = expected
|
25
|
+
else
|
26
|
+
expected_file = "#{dir}/expected"
|
27
|
+
File.open(expected_file, "w") {|io| io.write(expected)}
|
28
|
+
end
|
29
|
+
|
21
30
|
actual_file = "#{dir}/actual"
|
22
|
-
File.open(expected_file, "w") {|io| io.write(expected)}
|
23
31
|
File.open(actual_file, "w") {|io| io.write(actual)}
|
24
32
|
|
25
33
|
difftool = WINDOWS ? File.dirname(__FILE__) + "/../../bin/diff.exe" : "diff"
|
26
|
-
|
27
|
-
|
34
|
+
e = RSCM::PathConverter.filepath_to_nativepath(expected_file, false)
|
35
|
+
a = RSCM::PathConverter.filepath_to_nativepath(actual_file, false)
|
36
|
+
cmd = "#{difftool} --strip-trailing-cr #{e} #{a}"
|
37
|
+
IO.popen(cmd) do |io|
|
38
|
+
yield io, cmd
|
28
39
|
end
|
29
40
|
end
|
30
41
|
module_function :diff
|