Class: RSCM::Cvs

Inherits:
Base show all
Defined in:
lib/rscm/scm/cvs.rb

Overview

RSCM implementation for CVS.

You need a cvs executable on the PATH in order for it to work.

NOTE: On Cygwin this has to be the win32 build of cvs and not the Cygwin one.

Instance Attribute Summary collapse

Attributes inherited from Base

#checkout_dir

Instance Method Summary collapse

Methods inherited from Base

#==, #checkout_commandline, classes, #edit, register, #to_yaml_properties, #transactional?, #update_commandline

Constructor Details

#initialize(root = nil, mod = nil, branch = nil, password = nil) ⇒ Cvs

Returns a new instance of Cvs.



28
29
30
# File 'lib/rscm/scm/cvs.rb', line 28

def initialize(root=nil, mod=nil, branch=nil, password=nil)
  @root, @mod, @branch, @password = root, mod, branch, password
end

Instance Attribute Details

#branchObject

Returns the value of attribute branch.



23
24
25
# File 'lib/rscm/scm/cvs.rb', line 23

def branch
  @branch
end

#modObject

Returns the value of attribute mod.



20
21
22
# File 'lib/rscm/scm/cvs.rb', line 20

def mod
  @mod
end

#passwordObject

Returns the value of attribute password.



26
27
28
# File 'lib/rscm/scm/cvs.rb', line 26

def password
  @password
end

#rootObject

Returns the value of attribute root.



17
18
19
# File 'lib/rscm/scm/cvs.rb', line 17

def root
  @root
end

Instance Method Details

#add(relative_filename) ⇒ Object



37
38
39
# File 'lib/rscm/scm/cvs.rb', line 37

def add(relative_filename)
  cvs(@checkout_dir, "add #{relative_filename}")
end

#apply_label(label) ⇒ Object



115
116
117
# File 'lib/rscm/scm/cvs.rb', line 115

def apply_label(label)
  cvs(@checkout_dir, "tag -c #{label}")
end

#can_create_central?Boolean

Returns:

  • (Boolean)


195
196
197
198
199
200
201
# File 'lib/rscm/scm/cvs.rb', line 195

def can_create_central?
  begin
    local?
  rescue
    false
  end
end

#central_exists?Boolean

Returns:

  • (Boolean)


186
187
188
189
190
191
192
193
# File 'lib/rscm/scm/cvs.rb', line 186

def central_exists?
  if(local?)
    File.exists?("#{path}/CVSROOT/loginfo")
  else
    # don't know. assume yes.
    true
  end
end

#checked_out?Boolean

Returns:

  • (Boolean)


207
208
209
210
# File 'lib/rscm/scm/cvs.rb', line 207

def checked_out?
  rootcvs = File.expand_path("#{checkout_dir}/CVS/Root")
  File.exists?(rootcvs)
end

#checkout(to_identifier = nil, simulate = false) ⇒ Object

The extra simulate parameter is not in accordance with the AbstractSCM API, but it’s optional and is only being used from within this class (uptodate? method).



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
# File 'lib/rscm/scm/cvs.rb', line 50

def checkout(to_identifier=nil, simulate=false)
  checked_out_files = []
  if(checked_out?)
    path_regex = /^[U|P] (.*)/
    cvs(@checkout_dir, update_command(to_identifier), simulate) do |line|
      if(line =~ path_regex)
        path = $1.chomp
        yield path if block_given?
        checked_out_files << path
      end
    end
  else
    prefix = File.basename(@checkout_dir)
    path_regex = /^[U|P] #{prefix}\/(.*)/
    # This is a workaround for the fact that -d . doesn't work - must be an existing sub folder.
    FileUtils.mkdir_p(@checkout_dir) unless File.exist?(@checkout_dir)
    target_dir = File.basename(@checkout_dir)
    run_checkout_command_dir = File.dirname(@checkout_dir)
    # -D is sticky, but subsequent updates will reset stickiness with -A
    cvs(run_checkout_command_dir, checkout_command(target_dir, to_identifier), simulate) do |line|
      if(line =~ path_regex)
        path = $1.chomp
        yield path if block_given?
        checked_out_files << path
      end
    end
  end
  checked_out_files
end

#commit(message) ⇒ Object



80
81
82
# File 'lib/rscm/scm/cvs.rb', line 80

def commit(message)
  cvs(@checkout_dir, commit_command(message))
end

#create_centralObject



176
177
178
179
180
# File 'lib/rscm/scm/cvs.rb', line 176

def create_central
  raise "Can't create central CVS repository for #{root}" unless can_create_central?
  File.mkpath(path)
  cvs(path, "init")
end

#destroy_centralObject



182
183
184
# File 'lib/rscm/scm/cvs.rb', line 182

def destroy_central
  FileUtils.rm_rf(path)
end

#diff(change) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/rscm/scm/cvs.rb', line 99

def diff(change)
  with_working_dir(@checkout_dir) do
    opts = case change.status
      when /#{RevisionFile::MODIFIED}/; "#{revision_option(change.previous_native_revision_identifier)} #{revision_option(change.native_revision_identifier)}"
      when /#{RevisionFile::DELETED}/; "#{revision_option(change.previous_native_revision_identifier)}"
      when /#{RevisionFile::ADDED}/; "#{revision_option(Time.epoch)} #{revision_option(change.native_revision_identifier)}"
    end
    # IMPORTANT! CVS NT has a bug in the -N diff option
    # http://www.cvsnt.org/pipermail/cvsnt-bugs/2004-November/000786.html
    cmd = command_line("diff -Nu #{opts} #{change.path}")
    Better.popen(cmd, "r", 1) do |io|
      return(yield(io))
    end
  end
end

#import_central(dir, message) ⇒ Object



32
33
34
35
# File 'lib/rscm/scm/cvs.rb', line 32

def import_central(dir, message)
  modname = File.basename(dir)
  cvs(dir, "import -m \"#{message}\" #{modname} VENDOR START")
end

#install_trigger(trigger_command, trigger_files_checkout_dir) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rscm/scm/cvs.rb', line 119

def install_trigger(trigger_command, trigger_files_checkout_dir)
  raise "mod can't be null or empty" if (mod.nil? || mod == "")

  root_cvs = create_root_cvs(trigger_files_checkout_dir)
  root_cvs.checkout
  with_working_dir(trigger_files_checkout_dir) do
    trigger_line = "#{mod} #{trigger_command}\n"
    File.open("loginfo", File::WRONLY | File::APPEND) do |file|
      file.puts(trigger_line)
    end
    begin
      root_cvs.commit("Installed trigger for CVS module '#{mod}'")
    rescue
      raise "Couldn't commit the trigger back to CVS. Try to manually check out CVSROOT/loginfo, " +
      "add the following line and commit it back:\n\n#{trigger_line}"
    end
  end
end

#move(relative_src, relative_dest) ⇒ Object



41
42
43
44
45
46
# File 'lib/rscm/scm/cvs.rb', line 41

def move(relative_src, relative_dest)
  FileUtils.mv(@checkout_dir + '/' + relative_src, @checkout_dir + '/' + relative_dest, :force=>true)
  cvs(@checkout_dir, "rm #{relative_src}")
  # This will fail if the directories are new. More advanced support for adding can be added if needed.
  cvs(@checkout_dir, "add #{relative_dest}")
end

#revisions(from_identifier, to_identifier = Time.infinity) ⇒ Object



94
95
96
97
# File 'lib/rscm/scm/cvs.rb', line 94

def revisions(from_identifier, to_identifier=Time.infinity)
  checkout(to_identifier) unless uptodate?(to_identifier) # must checkout to get revisions
  parse_log(changes_command(from_identifier, to_identifier))
end

#supports_trigger?Boolean

Returns:

  • (Boolean)


203
204
205
# File 'lib/rscm/scm/cvs.rb', line 203

def supports_trigger?
  true
end

#trigger_installed?(trigger_command, trigger_files_checkout_dir) ⇒ Boolean

Returns:

  • (Boolean)


138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/rscm/scm/cvs.rb', line 138

def trigger_installed?(trigger_command, trigger_files_checkout_dir)
  loginfo_line = "#{mod} #{trigger_command}"
  regex = Regexp.new(Regexp.escape(loginfo_line))

  root_cvs = create_root_cvs(trigger_files_checkout_dir)
  begin
    root_cvs.checkout
    loginfo = File.join(trigger_files_checkout_dir, "loginfo")
    return false if !File.exist?(loginfo)

    # returns true if commented out. doesn't modify the file.
    in_local_copy = LineEditor.comment_out(File.new(loginfo), regex, "# ", "")
    # Also verify that loginfo has been committed back to the repo
    entries = File.join(trigger_files_checkout_dir, "CVS", "Entries")
    committed = File.mtime(entries) >= File.mtime(loginfo)

    in_local_copy && committed
  rescue Exception => e
    $stderr.puts(e.message)
    $stderr.puts(e.backtrace.join("\n"))
    false
  end
end

#uninstall_trigger(trigger_command, trigger_files_checkout_dir) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/rscm/scm/cvs.rb', line 162

def uninstall_trigger(trigger_command, trigger_files_checkout_dir)
  loginfo_line = "#{mod} #{trigger_command}"
  regex = Regexp.new(Regexp.escape(loginfo_line))

  root_cvs = create_root_cvs(trigger_files_checkout_dir)
  root_cvs.checkout
  loginfo_path = File.join(trigger_files_checkout_dir, "loginfo")
  File.comment_out(loginfo_path, regex, "# ")
  with_working_dir(trigger_files_checkout_dir) do
    root_cvs.commit("Uninstalled trigger for CVS mod '#{mod}'")
  end
  raise "Couldn't uninstall/commit trigger to loginfo" if trigger_installed?(trigger_command, trigger_files_checkout_dir)
end

#uptodate?(identifier) ⇒ Boolean

Returns:

  • (Boolean)


84
85
86
87
88
89
90
91
92
# File 'lib/rscm/scm/cvs.rb', line 84

def uptodate?(identifier)
  if(!checked_out?)
    return false
  end

  # simulate a checkout
  files = checkout(identifier, true)
  files.empty?
end