rscm 0.2.1.1404 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/README +34 -23
  2. data/Rakefile +24 -29
  3. data/bin/touch.exe +0 -0
  4. data/lib/rscm.rb +6 -3
  5. data/lib/rscm/annotations.rb +26 -7
  6. data/lib/rscm/{abstract_scm.rb → base.rb} +109 -71
  7. data/lib/rscm/better.rb +16 -0
  8. data/lib/rscm/logging.rb +11 -5
  9. data/lib/rscm/path_converter.rb +9 -16
  10. data/lib/rscm/revision.rb +201 -0
  11. data/lib/rscm/revision_file.rb +71 -0
  12. data/lib/rscm/scm/clearcase.rb +7 -7
  13. data/lib/rscm/scm/cvs.rb +69 -70
  14. data/lib/rscm/scm/cvs_log_parser.rb +29 -29
  15. data/lib/rscm/scm/darcs.rb +82 -34
  16. data/lib/rscm/scm/darcs_log_parser.rb +65 -0
  17. data/lib/rscm/scm/monotone.rb +249 -77
  18. data/lib/rscm/scm/monotone_log_parser.rb +57 -43
  19. data/lib/rscm/scm/mooky.rb +3 -3
  20. data/lib/rscm/scm/perforce.rb +196 -134
  21. data/lib/rscm/scm/star_team.rb +10 -10
  22. data/lib/rscm/scm/subversion.rb +106 -77
  23. data/lib/rscm/scm/subversion_log_parser.rb +76 -47
  24. data/lib/rscm/time_ext.rb +2 -116
  25. data/test/rscm/annotations_test.rb +15 -2
  26. data/test/rscm/{abstract_scm_test.rb → base_test.rb} +3 -3
  27. data/test/rscm/difftool_test.rb +9 -3
  28. data/test/rscm/generic_scm_tests.rb +195 -124
  29. data/test/rscm/revision_fixture.rb +20 -0
  30. data/test/rscm/revision_test.rb +129 -0
  31. data/test/rscm/{changesets.yaml → revisions.yaml} +10 -10
  32. data/test/rscm/scm/clearcase.log +608 -0
  33. data/test/rscm/scm/clearcase_test.rb +39 -0
  34. data/test/rscm/scm/cvs_log_parser_test.rb +73 -73
  35. data/test/rscm/scm/cvs_test.rb +1 -1
  36. data/test/rscm/scm/darcs_log_parser_test.rb +171 -0
  37. data/test/rscm/scm/monotone_log_parser_test.rb +49 -31
  38. data/test/rscm/scm/monotone_test.rb +3 -2
  39. data/test/rscm/scm/p4client_test.rb +33 -0
  40. data/test/rscm/scm/perforce_test.rb +25 -3
  41. data/test/rscm/scm/star_team.rb +9 -9
  42. data/test/rscm/scm/subversion_log_parser_test.rb +107 -47
  43. metadata +17 -13
  44. data/lib/multipart.rb +0 -95
  45. data/lib/rscm/RSS.txt +0 -41
  46. data/lib/rscm/changes.rb +0 -268
  47. data/lib/rscm/example.yaml +0 -21
  48. data/lib/rubyforge_file_publisher.rb +0 -176
  49. data/test/rscm/changes_fixture.rb +0 -20
  50. data/test/rscm/changes_test.rb +0 -129
data/README CHANGED
@@ -1,6 +1,6 @@
1
- = RSCM - Ruby Source Control Management (0.2.0)
1
+ = RSCM - Ruby Source Control Management (0.3.0)
2
2
 
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:
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
 
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)
@@ -8,15 +8,25 @@ RSCM is to SCM what DBI/JDBC/ODBC are to databases - an SCM-independent API for
8
8
  * Add and commit files
9
9
  * Manipluate triggers
10
10
 
11
+ Although RSCM's main focus is operations on a working copy of an SCM repository, the API also allows some level of interaction
12
+ with the SCM repository itself, like creating new repositories.
13
+
11
14
  == Download
12
15
 
13
16
  RSCM is available as a RubyGem, and can be installed like this:
14
17
 
15
18
  gem install rscm
16
19
 
20
+ (You may need administer access to do this on a POSIX system).
17
21
  If you want the latest and greatest, you can get the sources, which live alongside DamageControl's sources:
18
22
 
19
- http://damagecontrol.codehaus.org/Installing
23
+ * See the DamageControl Developer Guide at http://hieraki.lavalamp.ca/
24
+
25
+ == Team
26
+ * Aslak Hellesoy - All
27
+ * Steven Baker - Monotone
28
+ * Jon Tirsen - CVS, Subversion
29
+ * Yogi Kulkarni - Perforce
20
30
 
21
31
  == Supported SCMs
22
32
 
@@ -30,7 +40,7 @@ In progress:
30
40
  * ClearCase -http://www-306.ibm.com/software/awdtools/clearcase (half way there)
31
41
  * Darcs - http://www.abridgegame.org/darcs (very incomplete)
32
42
  * Monotone - http://www.venge.net/monotone (half way there)
33
-
43
+
34
44
  Planned:
35
45
 
36
46
  Loads! All of them! How to add support for a new one is described further down in this file.
@@ -46,29 +56,30 @@ Here is an example of how to use RSCM to get a list of changesets from a CVS rep
46
56
  require 'rscm'
47
57
 
48
58
  scm = RSCM::Subversion.new("svn://some.server/some/path/trunk", "trunk")
59
+ scm.checkout_dir = "/my/working/copy"
49
60
 
50
- scm.checkout("mycheckout")
51
- changesets = scm.changesets("mycheckout", Time.utc(2004, 11, 10, 12, 34, 22))
52
- changesets.each do |changeset|
53
- puts changeset
61
+ scm.checkout
62
+ revisions = scm.revisions(Time.utc(2004, 11, 10, 12, 34, 22))
63
+ revisions.each do |revision|
64
+ puts revision # or do something more funky with it
54
65
  end
55
66
 
56
67
  === Using visitors
57
68
 
58
- Although ChangeSets and ChangeSet support external iteration (as in the example above), the preferred way
59
- to operate on them is to let a ChangeSets object +accept+ a visitor. A visitor
69
+ Although the Revisions and Revision classes support external iteration
70
+ (with +each+ as in the example above), they also support
71
+ visitor traversal via their +accept+ methods. A visitor
60
72
  must respond to the following methods:
61
73
 
62
- def visit_changesets(changesets); end
63
- def visit_changeset(changeset); end
64
- def visit_change(change); end
74
+ def visit_revisions(revisions); end
75
+ def visit_revision(revision); end
76
+ def visit_file(revision_file); end
65
77
 
66
78
  === Getting diffs
67
79
 
68
- RSCM allows you to get diffs for changesets. This is done in the following way:
69
-
70
- See the DamageControl sources for more detailed examples (DamageControl persists diffs to disk
71
- and presents them as colourised diffs in its user interface).
80
+ RSCM allows you to get diffs for changesets. See the DamageControl sources for more detailed
81
+ examples (DamageControl persists diffs to disk and presents them as colourised diffs in its
82
+ user interface).
72
83
 
73
84
  == Future plans
74
85
 
@@ -84,7 +95,7 @@ the central SCM and one that you set up on your local machine.
84
95
  = Implementing support for a new SCM
85
96
 
86
97
  We'd be happy to receive contributions for more SCMs. You can always
87
- file a JIRA issue and hope for someone to implement it for you, or
98
+ file a JIRA issue (http://jira.codehaus.org/browse/DC) and hope for someone to implement it for you, or
88
99
  you can do it yourself. The rest of this file should get you started.
89
100
 
90
101
  N.B. IF YOU START IMPLEMENTING A NEW RSCM PLUGIN, PLEASE SUBMIT YOUR CODE
@@ -105,7 +116,7 @@ acceptance test suite for RSCM. By doing this you'll actually follow a TDD
105
116
  approach for your new Mooky class - except that the tests are already written
106
117
  for you!
107
118
 
108
- IMPORTANT NOTE: If your SCM doesn't provide an easy way to create new local repositories
119
+ IMPORTANT NOTE: If your SCM doesn't provide an easy way to create new local repositories
109
120
  (such as with StarTeam) you're probably better off writing the tests from scratch and not
110
121
  include GenericSCMTests. Instead, just make sure you have an SCM repository set up somewhere
111
122
  and write tests to work against that repository. This way you won't be able to pass the
@@ -162,8 +173,8 @@ You can reuse these classes for other Java based SCMs (if there are any, I don't
162
173
 
163
174
  == Web interface (DamageControl only)
164
175
 
165
- DamageControl automatically detects new SCM classes in RSCM and generates a default web interface.
166
-
176
+ DamageControl automatically detects new SCM classes in RSCM and generates a default web interface.
177
+
167
178
  = Building RSCM
168
179
  This section is for developers who are new to ruby development and do not already know how to build and install Ruby gems.
169
180
 
@@ -178,6 +189,6 @@ Now change to the RSCM root directory and type
178
189
 
179
190
  This will create a gem for RSCM. To install this gem, you have to change to the pgk directory and type
180
191
 
181
- sudo gem install pkg/rscm-0.1.0.gem
192
+ sudo gem install pkg/rscm-0.3.0.gem
182
193
 
183
- Now you can use RSCM in other Ruby apps.
194
+ Now you can use RSCM in other Ruby apps with a simple require 'rscm'.
data/Rakefile CHANGED
@@ -4,14 +4,13 @@ require 'rake/testtask'
4
4
  require 'rake/rdoctask'
5
5
  require 'rake/packagetask'
6
6
  require 'rake/gempackagetask'
7
- require 'rake/contrib/compositepublisher'
8
7
  require 'rake/contrib/sshpublisher'
9
8
  require 'rake/contrib/rubyforgepublisher'
10
- require 'lib/rubyforge_file_publisher'
9
+ require 'xforge'
11
10
 
12
11
  PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
13
12
  PKG_NAME = 'rscm'
14
- PKG_VERSION = '0.2.1' + PKG_BUILD
13
+ PKG_VERSION = '0.3.0' + PKG_BUILD
15
14
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
16
15
 
17
16
  desc "Default Task"
@@ -22,9 +21,11 @@ task :all => [:ant, :gem]
22
21
  # To run a specific test: rake test TEST=path/to/test
23
22
  fl = FileList.new('test/**/*_test.rb')
24
23
  fl.exclude('test/**/mooky*.rb')
25
- fl.exclude('test/**/monotone*.rb') # Incomplete/unsupported for now - reactivate when more complete!
24
+ #fl.exclude('test/**/monotone*.rb') # Incomplete/unsupported for now - reactivate when more complete!
25
+ fl.exclude('test/**/clearcase*.rb') # Incomplete/unsupported for now - reactivate when more complete!
26
26
  fl.exclude('test/**/darcs*.rb') # Incomplete/unsupported for now - reactivate when more complete!
27
- fl.exclude('test/**/perforce*.rb') # Incomplete/unsupported for now - reactivate when more complete!
27
+ #fl.exclude('test/**/perforce*.rb') # Incomplete/unsupported for now - reactivate when more complete!
28
+ #fl.exclude('test/**/p4client*.rb') # Incomplete/unsupported for now - reactivate when more complete!
28
29
  fl.exclude('test/**/starteam*.rb') # Too bloody hard to test without a StarTeam server license! Tested ad-hoc.
29
30
  Rake::TestTask.new { |t|
30
31
  t.libs << "test"
@@ -109,29 +110,23 @@ else
109
110
  end
110
111
  end
111
112
 
112
- task :publish => [:rdoc] do
113
- publisher = Rake::CompositePublisher.new
114
- publisher.add Rake::RubyForgePublisher.new('rscm', 'aslak_hellesoy')
115
- publisher.upload
116
-
117
- # RUBYFORGE_GROUP_ID = 490
118
- # RUBYFORGE_PACKAGE_ID = 552
119
- # RUBYFORGE_RELEASE_NAME = "rakedrelease"
120
- #
121
- # Rake::RubyForgeFilePublisher.new(
122
- # RUBYFORGE_GROUP_ID,
123
- # "aslak_hellesoy",
124
- # "README",
125
- # #"pkg/#{PKG_FILE_NAME}.gem",
126
- # RUBYFORGE_PACKAGE_ID,
127
- # RUBYFORGE_RELEASE_NAME
128
- # ) do |p|
129
- # p.type_id = 8100
130
- # p.processor_id = 2000
131
- # p.preformatted = 1
132
- # p.release_name = "come on"
133
- # p.release_changes = "now"
134
- # p.release_date = Time.utc(2005, 2, 19, 23, 42, 0)
135
- # end
113
+ task :release => [:publish_doc, :publish_files]
114
+
115
+ task :publish_files => [:gem] do
116
+ release_files = FileList[
117
+ "pkg/#{PKG_FILE_NAME}.gem",
118
+ "CHANGES"
119
+ ]
120
+
121
+ Rake::XForge::Release.new(PKG_NAME) do |xf|
122
+ # Never hardcode user name and password in the Rakefile!
123
+ xf.user_name = ENV['RUBYFORGE_USER']
124
+ xf.password = ENV['RUBYFORGE_PASSWORD']
125
+ xf.files = release_files.to_a
126
+ xf.release_name = "XForge #{PKG_VERSION}"
127
+ end
128
+ end
136
129
 
130
+ task :publish_doc => [:rdoc] do
131
+ publisher = Rake::RubyForgePublisher.new('rscm', 'aslak_hellesoy')
137
132
  end
Binary file
@@ -1,5 +1,8 @@
1
- require 'rscm/abstract_scm'
2
- require 'rscm/changes'
1
+ require 'rscm/annotations'
2
+ require 'rscm/path_converter'
3
3
  require 'rscm/logging'
4
+ require 'rscm/better'
5
+ require 'rscm/base'
6
+ require 'rscm/revision'
7
+ require 'rscm/revision_file'
4
8
  require 'rscm/time_ext'
5
- require 'rscm/abstract_scm'
@@ -1,5 +1,7 @@
1
1
  class Class
2
+
2
3
  @@anns = {}
4
+ @@attr_anns = {}
3
5
 
4
6
  # Defines annotation(s) for the next defined +attr_reader+ or
5
7
  # +attr_accessor+. The +anns+ argument should be a Hash defining annotations
@@ -23,23 +25,24 @@ class Class
23
25
  # You may also use annotations to specify more programmatically meaningful metadata. More power to you.
24
26
  #
25
27
  def ann(anns)
26
- $attr_anns ||= {}
27
- $attr_anns.merge!(anns)
28
+ @@attr_anns ||= {}
29
+ @@attr_anns.merge!(anns)
28
30
  end
29
-
31
+
30
32
  def method_missing(sym, *args) #:nodoc:
31
33
  anns = @@anns[self]
32
- return superclass.method_missing(sym, *args) if(anns.nil?)
33
- anns[sym]
34
+ return anns[sym] if(anns && anns[sym])
35
+ return superclass.method_missing(sym, *args) if superclass
36
+ return {}
34
37
  end
35
38
 
36
39
  alias old_attr_reader attr_reader #:nodoc:
37
40
  def attr_reader(*syms) #:nodoc:
38
41
  @@anns[self] ||= {}
39
42
  syms.each do |sym|
40
- @@anns[self][sym] = $attr_anns.dup if $attr_anns
43
+ @@anns[self][sym] = @@attr_anns.dup if @@attr_anns
41
44
  end
42
- $attr_anns = nil
45
+ @@attr_anns = nil
43
46
  old_attr_reader(*syms)
44
47
  end
45
48
 
@@ -48,3 +51,19 @@ class Class
48
51
  attr_writer(*syms)
49
52
  end
50
53
  end
54
+
55
+ class Object
56
+ def anns(attr_name)
57
+ self.class.send(attr_name)
58
+ end
59
+
60
+ def __attr_accessors
61
+ attrs = []
62
+ methods.each do |method|
63
+ if(method =~ /(.*)=/)
64
+ attrs << "@#{$1}" if methods.index($1) && $1 != "=="
65
+ end
66
+ end
67
+ attrs.sort
68
+ end
69
+ end
@@ -1,44 +1,57 @@
1
1
  require 'fileutils'
2
- require 'rscm/changes'
2
+ require 'rscm/revision'
3
3
  require 'rscm/path_converter'
4
4
  require 'rscm/annotations'
5
5
 
6
- class String
7
- # Turns a String into a Time or an int
8
- def to_identifier
9
- if(self =~ /20\d\d\d\d\d\d\d\d\d\d\d\d/)
10
- # Assume it's a timestamp string - convert to time.
11
- Time.parse_ymdHMS(self)
12
- else
13
- # Assume it's an arbitrary integer.
14
- self.to_i
15
- end
16
- end
17
- end
18
-
19
- class Time
20
- def to_s
21
- self.ymdHMS
22
- end
23
- end
24
-
25
6
  module RSCM
26
7
  # This class defines the RSCM API. The documentation of the various methods
27
- # uses CVS' terminology.
8
+ # uses CVS and Subversion's terminology. (For example, checkout means 'get working copy',
9
+ # not 'lock for private edit' as in ClearCase or VSS terminology).
10
+ #
11
+ # Concrete subclasses of this class provide an API to manage a local working copy
12
+ # as well as an associated 'central' repository. The main responsibility is working
13
+ # copy operations:
14
+ #
15
+ # * checkout
16
+ # * revisions
17
+ # * uptodate?
18
+ # * checked_out?
19
+ # * diff
20
+ # * edit
21
+ #
22
+ # In addition to operations related to working copies, the same instance should provide
23
+ # methods to administer the working copy's associated 'central' repository. These are:
24
+ #
25
+ # * central_exists?
26
+ # * create_central
27
+ # * can_create_central?
28
+ # * import_central
29
+ # * supports_trigger? # TODO: rename to can_install_trigger?
30
+ # * trigger_installed?
31
+ # * install_trigger
32
+ # * uninstall_trigger
33
+ #
34
+ # Some methods are a bit fuzzy with respect to their relevance to the working copy or
35
+ # the associated central repository, as it depends on the nature of the individual underlying
36
+ # SCMs. These methods are:
37
+ #
38
+ # * label
39
+ # * name
40
+ # * transactional?
41
+ # * checkout_command_line
42
+ # * update_command_line
28
43
  #
29
44
  # Some of the methods in this API use +from_identifier+ and +to_identifier+.
30
45
  # These identifiers can be either a UTC Time (according to the SCM's clock)
31
- # or a String representing a label (according to the SCM's label system).
46
+ # or a String or Integer representing a label/revision
47
+ # (according to the SCM's native label/revision scheme).
32
48
  #
33
- # If +from_identifier+ or +to_identifier+ are +nil+ they respectively represent
34
- # epoch or the infinite future.
49
+ # If +from_identifier+ or +to_identifier+ are +nil+ they should respectively default to
50
+ # Time.epoch or Time.infinite.
35
51
  #
36
- # Most of the methods take a mandatory +checkout_dir+ - even if this may seem
37
- # unnecessary. The reason is that some SCMs require a working copy to be checked
38
- # out in order to perform certain operations. In order to develop portable code,
39
- # you should always pass in a non +nil+ value for +checkout_dir+.
52
+ # TODO: rename this superclass to 'Base'
40
53
  #
41
- class AbstractSCM
54
+ class Base
42
55
  include FileUtils
43
56
 
44
57
  @@classes = []
@@ -51,27 +64,35 @@ module RSCM
51
64
 
52
65
  # Load all sources under scm, so SCM classes can register themselves
53
66
  Dir[File.dirname(__FILE__) + "/scm/*.rb"].each do |src|
54
- load(src)
67
+ require src
55
68
  end
56
69
 
57
70
 
58
- # TODO: Make changesets yield changesets as they are determined, to avoid
71
+ # TODO: Make revisions yield revisions as they are determined, to avoid
59
72
  # having to load them all into memory before the method exits. Careful not to
60
- # use yielded changesets to do another scm hit - like get diffs. Some SCMs
73
+ # use yielded revisions to do another scm hit - like get diffs. Some SCMs
61
74
  # might dead lock on this. Implement a guard for that.
62
75
  # TODO: Add some visitor support here too?
63
76
 
64
77
  public
65
78
 
79
+ attr_accessor :checkout_dir
80
+
81
+ def to_yaml_properties
82
+ props = instance_variables
83
+ props.delete("@checkout_dir")
84
+ props.sort!
85
+ end
86
+
66
87
  # Whether the physical SCM represented by this instance exists.
67
88
  #
68
- def exists?
89
+ def central_exists?
69
90
  # The default implementation assumes yes - override if it can be
70
91
  # determined programmatically.
71
92
  true
72
93
  end
73
94
 
74
- # Whether or not this SCM is transactional.
95
+ # Whether or not this SCM is transactional (atomic).
75
96
  #
76
97
  def transactional?
77
98
  false
@@ -85,18 +106,29 @@ module RSCM
85
106
  # This method should throw an exception if the repository cannot be created (for
86
107
  # example if the repository is 'remote' or if it already exists).
87
108
  #
88
- def create
109
+ def create_central
110
+ raise "Not implemented"
111
+ end
112
+
113
+ # Destroysthe central repository. Shuts down any server processes and deletes the repository.
114
+ # WARNING: calling this may result in loss of data. Only call this if you really want to wipe it out for good!
115
+ def destroy_central
89
116
  end
90
117
 
91
118
  # Whether a repository can be created.
92
119
  #
93
- def can_create?
120
+ def can_create_central?
94
121
  false
95
122
  end
96
123
 
97
- # Recursively imports files from a directory
124
+ # Adds +relative_filename+ to the working copy.
125
+ def add(relative_filename)
126
+ end
127
+
128
+ # Recursively imports files from a directory into the central scm
98
129
  #
99
- def import(dir, message)
130
+ def import_central(dir, message)
131
+ raise "Not implemented"
100
132
  end
101
133
 
102
134
  # The display name of this SCM
@@ -106,23 +138,19 @@ module RSCM
106
138
  self.class.name
107
139
  end
108
140
 
109
- # Gets the label for the working copy currently checked out in +checkout_dir+.
110
- #
111
- def label(checkout_dir)
112
- end
113
-
114
141
  # Open a file for edit - required by scms that checkout files in read-only mode e.g. perforce
115
142
  #
116
143
  def edit(file)
117
144
  end
118
145
 
119
- # Checks out or updates contents from an SCM to +checkout_dir+ - a local working copy.
146
+ # Checks out or updates contents from a central SCM to +checkout_dir+ - a local working copy.
120
147
  # If this is a distributed SCM, this method should create a 'working copy' repository
121
- # if one doesn't already exist.
148
+ # if one doesn't already exist. Then the contents of the central SCM should be pulled into
149
+ # the working copy.
122
150
  #
123
151
  # The +to_identifier+ parameter may be optionally specified to obtain files up to a
124
- # particular time or label. +time_label+ should either be a Time (in UTC - according to
125
- # the clock on the SCM machine) or a String - reprsenting a label.
152
+ # particular time or label. +to_identifier+ should either be a Time (in UTC - according to
153
+ # the clock on the SCM machine) or a String - reprsenting a label or revision.
126
154
  #
127
155
  # This method will yield the relative file name of each checked out file, and also return
128
156
  # them in an array. Only files, not directories, should be yielded/returned.
@@ -130,13 +158,14 @@ module RSCM
130
158
  # This method should be overridden for SCMs that are able to yield checkouts as they happen.
131
159
  # For some SCMs this is not possible, or at least very hard. In that case, just override
132
160
  # the checkout_silent method instead of this method (should be protected).
133
- def checkout(checkout_dir, to_identifier=Time.infinity) # :yield: file
161
+ #
162
+ def checkout(to_identifier=Time.infinity) # :yield: file
134
163
  # the OS doesn't store file timestamps with fractions.
135
164
  before_checkout_time = Time.now.utc - 1
136
165
 
137
166
  # We expect subclasses to implement this as a protected method (unless this whole method is overridden).
138
- checkout_silent(checkout_dir, to_identifier)
139
- files = Dir["#{checkout_dir}/**/*"]
167
+ checkout_silent(to_identifier)
168
+ files = Dir["#{@checkout_dir}/**/*"]
140
169
  added = []
141
170
  files.each do |file|
142
171
  added << file if File.mtime(file).utc > before_checkout_time
@@ -154,45 +183,49 @@ module RSCM
154
183
  relative_added_file_paths
155
184
  end
156
185
 
157
- # Returns a ChangeSets object for the period specified by +from_identifier+
158
- # and +to_identifier+. See AbstractSCM for details about the parameters.
186
+ # Returns a Revisions object for the period specified by +from_identifier+ (exclusive, i.e. after)
187
+ # and +to_identifier+ (inclusive).
159
188
  #
160
- def changesets(checkout_dir, from_identifier, to_identifier=Time.infinity)
189
+ def revisions(from_identifier, to_identifier=Time.infinity)
161
190
  # Should be overridden by subclasses
162
- changesets = ChangeSets.new
163
- changesets.add(
164
- Change.new(
191
+ revisions = Revisions.new
192
+ revisions.add(
193
+ Revision.new(
165
194
  "up/the/chimney",
195
+ Revision::DELETED,
166
196
  "DamageControl",
167
- "The #{name} SCM class in #{__FILE__} doesn't\n" +
168
- "correctly implement the changesets method. This is\n" +
169
- "not a real changeset, but a hint to the developer to go and implement it.\n\n" +
197
+ "The #{name} class doesn't\n" +
198
+ "correctly implement the revisions method. This is\n" +
199
+ "not a real revision, but a hint to the developer to go and implement it.\n\n" +
170
200
  "Do It Now!",
171
201
  "999",
172
202
  Time.now.utc
173
203
  )
174
204
  )
175
- changesets
205
+ revisions
176
206
  end
177
207
 
178
- # Whether the working copy in +checkout_dir+ is in synch with the central
179
- # repository since +from_identifier+.
208
+ # Whether the working copy is in synch with the central
209
+ # repository's revision/time identified by +identifier+.
210
+ # If +identifier+ is nil, 'HEAD' of repository should be assumed.
180
211
  #
181
- def uptodate?(checkout_dir, from_identifier)
212
+ # TODO: rename to in_synch?
213
+ def uptodate?(identifier)
182
214
  # Suboptimal algorithm that works for all SCMs.
183
- # Subclasses can override this to increase efficiency.
215
+ # Subclasses can override this to improve efficiency.
184
216
 
185
- changesets(checkout_dir, from_identifier).empty?
217
+ revisions(identifier).empty?
186
218
  end
187
219
 
188
220
  # Whether the project is checked out from the central repository or not.
189
221
  # Subclasses should override this to check for SCM-specific administrative
190
222
  # files if appliccable
191
- def checked_out?(checkout_dir)
192
- File.exists?(checkout_dir)
223
+ def checked_out?
224
+ File.exists?(@checkout_dir)
193
225
  end
194
226
 
195
- # Whether triggers are supported by this SCM
227
+ # Whether triggers are supported by this SCM. A trigger is a command that can be executed
228
+ # upon a completed commit to the SCM.
196
229
  def supports_trigger?
197
230
  # The default implementation assumes no - override if it can be
198
231
  # determined programmatically.
@@ -206,31 +239,36 @@ module RSCM
206
239
  # Most implementations will ignore this parameter.
207
240
  #
208
241
  def install_trigger(trigger_command, install_dir)
242
+ raise "Not implemented"
209
243
  end
210
244
 
211
245
  # Uninstalls +trigger_command+ from the SCM.
212
246
  #
213
247
  def uninstall_trigger(trigger_command, install_dir)
248
+ raise "Not implemented"
214
249
  end
215
250
 
216
251
  # Whether the command denoted by +trigger_command+ is installed in the SCM.
217
252
  #
218
253
  def trigger_installed?(trigger_command, install_dir)
254
+ raise "Not implemented"
219
255
  end
220
256
 
221
257
  # The command line to run in order to check out a fresh working copy.
222
258
  #
223
259
  def checkout_commandline(to_identifier=Time.infinity)
260
+ raise "Not implemented"
224
261
  end
225
262
 
226
263
  # The command line to run in order to update a working copy.
227
264
  #
228
265
  def update_commandline(to_identifier=Time.infinity)
266
+ raise "Not implemented"
229
267
  end
230
268
 
231
269
  # Returns/yields an IO containing the unified diff of the change.
232
- def diff(checkout_dir, change, &block)
233
- return(yield("Diff not implemented"))
270
+ def diff(change, &block)
271
+ return(yield("Not implemented"))
234
272
  end
235
273
 
236
274
  def ==(other_scm)
@@ -243,7 +281,7 @@ module RSCM
243
281
 
244
282
  protected
245
283
 
246
- # Takes an array of +absolute_path+s and turn them into an array
284
+ # Takes an array of +absolute_paths+ and turns it into an array
247
285
  # of paths relative to +dir+
248
286
  #
249
287
  def to_relative(dir, absolute_paths)