Module: Subversion
- Includes:
- Extensions
- Defined in:
- lib/subwrap/subversion.rb,
lib/subwrap/subversion.rb,
lib/subwrap/svn_command.rb,
lib/subwrap/svn_command.rb,
lib/subwrap/svn_command.rb,
lib/subwrap/svn_command.rb,
lib/subwrap/subversion_extensions.rb
Overview
These are methods used by the SvnCommand for filtering and whatever else it needs… It could probably be moved into SvnCommand, but I thought it might be good to at least make it possible to use them apart from SvnCommand. Rename to Subversion::Filters ? Then each_unadded would be an odd man out.
Defined Under Namespace
Modules: Extensions Classes: Diff, Diffs, DiffsParser, ExternalsContainer, RevisionProperty, SvnCommand
Constant Summary collapse
- @@color =
True if you want output from svn to be colorized (useful if output is for human eyes, but not useful if using the output programatically)
false
- @@dry_run =
If true, will only output which command would have been executed but will not actually execute it.
false
- @@print_commands =
If true, will print all commands to the screen before executing them.
false
- @@cached_commands =
{}
Constants included from Extensions
Extensions::Interesting_status_flags, Extensions::Status_flags, Extensions::Uninteresting_status_flags
Class Method Summary collapse
-
.add(*args) ⇒ Object
Adds the given items to the repository.
-
.add_to_property(property, path, *new_lines) ⇒ Object
It’s easy to get/set properties, but less easy to add to a property.
-
.base_url(path_or_url = './') ⇒ Object
:todo: needs some serious unit-testing love.
- .cat(*args) ⇒ Object
- .commit(*args) ⇒ Object
- .delete_property(property, path = './') ⇒ Object
- .delete_revision_property(property_name, rev) ⇒ Object
-
.diff(*args) ⇒ Object
Returns the modifications to the working directory or URL specified in
args
. -
.diffs(*args) ⇒ Object
Parses the output from diff and returns an array of Diff objects.
-
.executable ⇒ Object
The location of the executable to be used to do: Is there a smarter/faster way to do this? (Could cache this result in .subwrap or somewhere, so we don’t have to do all this work on every invocation…).
- .export(path_or_url, target) ⇒ Object
-
.externalize(repo_url, options = {}) ⇒ Object
Adds the given repository URL (svn.yourcompany.com/path/to/something) as an svn:externals.
-
.externals_containers(path = './') ⇒ Object
Returns an array of ExternalsContainer objects representing all externals containers in the working directory specified by
path
. -
.externals_items(path = './') ⇒ Object
Returns an array of externals items.
-
.get_property(property, path = './') ⇒ Object
:todo: Stop assuming the svn: namespace.
- .get_revision_property(property_name, rev) ⇒ Object
- .help(*args) ⇒ Object
-
.ignore(*patterns) ⇒ Object
Sets the svn:ignore property based on the given
patterns
. - .info(*args) ⇒ Object
-
.latest_revision(path = './') ⇒ Object
Returns the revision number for head.
-
.latest_revision_for_path(path) ⇒ Object
Returns the revision number for the working directory(/file?) specified by
path
. -
.log(*args) ⇒ Object
Returns the raw output from svn log.
- .make_directory(dir) ⇒ Object
-
.make_executable(*paths) ⇒ Object
Marks the given items as being executable.
- .make_not_executable(*paths) ⇒ Object
-
.proplist(rev) ⇒ Object
Gets raw output of proplist command.
-
.remove(*args) ⇒ Object
Removes the given items from the repository and the disk.
-
.remove_force(*args) ⇒ Object
Removes the given items from the repository and the disk.
-
.remove_without_delete(*args) ⇒ Object
Removes the given items from the repository BUT NOT THE DISK.
- .repository_root(*args) ⇒ Object
- .repository_uuid(path_or_url = './') ⇒ Object
-
.revert(*args) ⇒ Object
Reverts the given items in the working copy.
-
.revision_properties(rev) ⇒ Object
Returns an array of RevisionProperty objects (name, value) for revisions currently set on the given
rev
Tessted by: ../../test/subversion_test.rb:test_revision_properties. -
.revision_properties_names(rev) ⇒ Object
Returns an array of the names of all revision properties currently set on the given
rev
Tessted by: ../../test/subversion_test.rb:test_revision_properties_names. -
.revisions(*args) ⇒ Object
Returns an array of RSCM::Revision objects.
- .root_url(*args) ⇒ Object
- .ruby_script?(file_path) ⇒ Boolean
- .set_property(property, value, path = './') ⇒ Object
- .set_revision_property(property_name, rev) ⇒ Object
-
.status(*args) ⇒ Object
Returns the status of items in the working directories
paths
. - .status_against_server(*args) ⇒ Object
-
.status_the_section_before_externals(path = './') ⇒ Object
The output from ‘svn status` is nicely divided into two “sections”: the section which pertains to the current working copy (not counting externals as part of the working copy) and then the section with status of all of the externals.
-
.under_version_control?(file = './', strict = false) ⇒ Boolean
By default, if you query a directory that is scheduled for addition but hasn’t been committed yet (node doesn’t have a UUID), then we will still return true, because it is scheduled to be under version control.
- .unignore(*patterns) ⇒ Object
- .update(*args) ⇒ Object
- .url(path_or_url = './') ⇒ Object
- .working_copy_root(directory = './') ⇒ Object
Class Method Details
.add(*args) ⇒ Object
Adds the given items to the repository. Items may contain wildcards.
63 64 65 |
# File 'lib/subwrap/subversion.rb', line 63 def self.add(*args) execute "add #{args.join ' '}" end |
.add_to_property(property, path, *new_lines) ⇒ Object
It’s easy to get/set properties, but less easy to add to a property. This method uses get/set to simulate add. It will uniquify lines, removing duplicates. (:todo: what if we want to set a property to have some duplicate lines?)
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/subwrap/subversion.rb', line 258 def self.add_to_property(property, path, *new_lines) # :todo: I think it's possible to have properties other than svn:* ... so if property contains a prefix (something:), use it; else default to 'svn:' # Get the current properties lines = self.get_property(property, path).split "\n" puts "Existing lines: #{lines.inspect}" if $debug # Add the new lines, delete empty lines, and uniqueify all elements lines.concat(new_lines).uniq! puts "After concat(new_lines).uniq!: #{lines.inspect}" if $debug lines.delete '' # Set the property puts "About to set propety to: #{lines.inspect}" if $debug self.set_property property, lines.join("\n"), path end |
.base_url(path_or_url = './') ⇒ Object
:todo: needs some serious unit-testing love
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
# File 'lib/subwrap/subversion.rb', line 379 def self.base_url(path_or_url = './') matches = info(path_or_url).match(/^Repository Root: (.+)/) matches && matches[1] # It appears that we might need to use this old way (which looks at 'URL'), since there is actually a handy property called "Repository Root" that we can look at. # base_url = nil # needed so that base_url variable isn't local to loop block (and reset during next iteration)! # started_using_dot_dots = false # loop do # matches = /^URL: (.+)/.match(info(path_or_url)) # if matches && matches[1] # base_url = matches[1] # else # break base_url # end # # # Keep going up the path, one directory at a time, until `svn info` no longer returns a URL (will probably eventually return 'svn: PROPFIND request failed') # if path_or_url.include?('/') && !started_using_dot_dots # path_or_url = File.dirname(path_or_url) # else # started_using_dot_dots = true # path_or_url = File.join(path_or_url, '..') # end # #puts 'going up to ' + path_or_url # end end |
.cat(*args) ⇒ Object
251 252 253 254 |
# File 'lib/subwrap/subversion.rb', line 251 def self.cat(*args) args = ['./'] if args.empty? execute("cat #{args.join ' '}") end |
.commit(*args) ⇒ Object
177 178 179 180 |
# File 'lib/subwrap/subversion.rb', line 177 def self.commit(*args) args = ['./'] if args.empty? execute("commit #{args.join ' '}") end |
.delete_property(property, path = './') ⇒ Object
283 284 285 |
# File 'lib/subwrap/subversion.rb', line 283 def self.delete_property(property, path = './') execute "propdel svn:#{property} #{path}" end |
.delete_revision_property(property_name, rev) ⇒ Object
286 287 288 |
# File 'lib/subwrap/subversion.rb', line 286 def self.delete_revision_property(property_name, rev) execute("propdel --revprop #{property_name} -r #{rev}").chomp end |
.diff(*args) ⇒ Object
Returns the modifications to the working directory or URL specified in args
.
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/subwrap/subversion.rb', line 220 def self.diff(*args) args = ['./'] if args.empty? diff = execute("diff #{"--diff-cmd colordiff" if color?} #{args.join ' '}") # Fix annoyance: You can't seem to do a diff on a file that was *added*. If you do -r 1:2 for a file that was *added* in 2, it will say it can't find the repository location for that file in r1. if diff =~ /Unable to find repository location for '.*' in revision/ and @allow_diffs_for_added_files != false args.map!(&:to_s) args.map_with_index! do |arg, i| if args[i-1].in? ['--revision', '-r'] arg.gsub(/\d+:/, '') elsif arg.in? ['--change', '-c'] arg.gsub(/-c|--change/, '-r') else arg end end diff = execute("cat #{args.join ' '}") #.to_enum(:each_line).map(&:chomp).map(&:green).join("\n") end diff end |
.diffs(*args) ⇒ Object
Parses the output from diff and returns an array of Diff objects.
242 243 244 245 246 247 248 249 |
# File 'lib/subwrap/subversion.rb', line 242 def self.diffs(*args) args = ['./'] if args.empty? raw_diffs = nil with_color! false do raw_diffs = diff(*args) end DiffsParser.new(raw_diffs).parse end |
.executable ⇒ Object
The location of the executable to be used to do: Is there a smarter/faster way to do this? (Could cache this result in .subwrap or somewhere, so we don’t have to do all this work on every invocation…)
442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/subwrap/subversion.rb', line 442 def self.executable # FileUtils.which('svn') would return our Ruby *wrapper* script for svn. We actually want to return here the binary/executable that we are # *wrapping* so we have to use whereis and then use the first one that is ''not'' a Ruby script. @@executable ||= FileUtils.whereis('svn') do |executable| if !self.ruby_script?(executable) # We want to wrap the svn binary provided by Subversion, not our custom replacement for that. return windows_platform? ? %{"#{executable}"} : executable end end raise 'svn binary not found' end |
.export(path_or_url, target) ⇒ Object
108 109 110 |
# File 'lib/subwrap/subversion.rb', line 108 def self.export(path_or_url, target) execute "export #{path_or_url} #{target}" end |
.externalize(repo_url, options = {}) ⇒ Object
Adds the given repository URL (svn.yourcompany.com/path/to/something) as an svn:externals.
Options may include:
-
:as
- overrides the default behavior of naming the checkout based on the last component of the repo path -
:local_path
- specifies where to set the externals property. Defaults to ‘.’ or the dirname ofas
ifas
is specified (for example,vendor/plugins
ifas
isvendor/plugins/plugin_name
).
93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/subwrap/subversion.rb', line 93 def self.externalize(repo_url, = {}) [:as] ||= File.basename(repo_url) #options[:as] = options[:as].ljust(29) # You can't set the externals of './' to 'vendor/plugins/foo http://example.com/foo' # Instead, you have to set the externals of 'vendor/plugins/' to 'foo http://example.com/foo' # This will make that correction for you automatically. [:local_path] ||= File.dirname([:as]) # Will be '.' if options[:as] has no dirname component. # Will be 'vendor/plugins' if options[:as] is 'vendor/plugins/plugin_name'. [:as] = File.basename([:as]) add_to_property 'externals', [:local_path], "#{[:as]} #{repo_url}" end |
.externals_containers(path = './') ⇒ Object
Returns an array of ExternalsContainer objects representing all externals containers in the working directory specified by path
.
208 209 210 211 212 213 214 215 216 217 |
# File 'lib/subwrap/subversion.rb', line 208 def self.externals_containers(path = './') # Using self.externals_items is kind of a cheap way to do this, and it results in some redundancy that we have to filter out # (using uniq_by), but it seemed more efficient than the alternative (traversing the entire directory tree and querying for # `svn prepget svn:externals` at each stop to see if the directory is an externals container). self.externals_items(path).map { |external_dir| ExternalsContainer.new(external_dir + '/..') }.uniq_by { |external| external.container_dir } end |
.externals_items(path = './') ⇒ Object
Returns an array of externals items. These are the actual externals listed in an svn:externals property. Example:
vendor/a
vendor/b
Where ‘vendor’ is an ExternalsContainer containing external items ‘a’ and ‘b’.
195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/subwrap/subversion.rb', line 195 def self.externals_items(path = './') status = status_the_section_before_externals(path) return [] if status.nil? status.select { |line| line =~ /^X/ }.map { |line| # Just keep the filename part line =~ /^X\s+(.+)/ $1 } end |
.get_property(property, path = './') ⇒ Object
:todo: Stop assuming the svn: namespace. What’s the point of a namespace if you only allow one of them?
276 277 278 |
# File 'lib/subwrap/subversion.rb', line 276 def self.get_property(property, path = './') execute "propget svn:#{property} #{path}" end |
.get_revision_property(property_name, rev) ⇒ Object
279 280 281 |
# File 'lib/subwrap/subversion.rb', line 279 def self.get_revision_property(property_name, rev) execute("propget --revprop #{property_name} -r #{rev}").chomp end |
.help(*args) ⇒ Object
321 322 323 |
# File 'lib/subwrap/subversion.rb', line 321 def self.help(*args) execute "help #{args.join(' ')}" end |
.ignore(*patterns) ⇒ Object
Sets the svn:ignore property based on the given patterns
. Each pattern is both the path (where the property gets set) and the property itself. For instance:
"log/*.log" would add "*.log" to the svn:ignore property on the log/ directory.
"log" would add "log" to the svn:ignore property on the ./ directory.
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/subwrap/subversion.rb', line 72 def self.ignore(*patterns) patterns.each do |pattern| path = File.dirname(pattern) path += '/' if path == '.' pattern = File.basename(pattern) add_to_property 'ignore', path, pattern end nil end |
.info(*args) ⇒ Object
368 369 370 371 |
# File 'lib/subwrap/subversion.rb', line 368 def self.info(*args) args = ['./'] if args.empty? execute "info #{args.join(' ')}" end |
.latest_revision(path = './') ⇒ Object
Returns the revision number for head.
332 333 334 335 336 337 338 339 340 |
# File 'lib/subwrap/subversion.rb', line 332 def self.latest_revision(path = './') (cached = @@cached_commands[:latest_revision][path]) and return cached url = url(path) #puts "Fetching latest revision from repository: #{url}" result = latest_revision_for_path(url).to_i @@cached_commands[:latest_revision][path] = result result end |
.latest_revision_for_path(path) ⇒ Object
Returns the revision number for the working directory(/file?) specified by path
343 344 345 346 347 348 349 350 351 |
# File 'lib/subwrap/subversion.rb', line 343 def self.latest_revision_for_path(path) # The revision returned by svn info seems to be a pretty reliable way to get this. Does anyone know of a better way? matches = info(path).match(/^Revision: (\d+)/) if matches matches[1].to_i else raise "Could not extract revision from #{info(path)}" end end |
.log(*args) ⇒ Object
Returns the raw output from svn log
326 327 328 329 |
# File 'lib/subwrap/subversion.rb', line 326 def self.log(*args) args = ['./'] if args.empty? execute "log #{args.join(' ')}" end |
.make_directory(dir) ⇒ Object
317 318 319 |
# File 'lib/subwrap/subversion.rb', line 317 def self.make_directory(dir) execute "mkdir #{dir}" end |
.make_executable(*paths) ⇒ Object
Marks the given items as being executable. Items may not contain wildcards.
150 151 152 153 154 |
# File 'lib/subwrap/subversion.rb', line 150 def self.make_executable(*paths) paths.each do |path| self.set_property 'executable', '', path end end |
.make_not_executable(*paths) ⇒ Object
155 156 157 158 159 |
# File 'lib/subwrap/subversion.rb', line 155 def self.make_not_executable(*paths) paths.each do |path| self.delete_property 'executable', path end end |
.proplist(rev) ⇒ Object
Gets raw output of proplist command
298 299 300 |
# File 'lib/subwrap/subversion.rb', line 298 def self.proplist(rev) execute("proplist --revprop -r #{rev}") end |
.remove(*args) ⇒ Object
Removes the given items from the repository and the disk. Items may contain wildcards.
113 114 115 |
# File 'lib/subwrap/subversion.rb', line 113 def self.remove(*args) execute "rm #{args.join ' '}" end |
.remove_force(*args) ⇒ Object
Removes the given items from the repository and the disk. Items may contain wildcards. To do: add a :force => true option to remove
119 120 121 |
# File 'lib/subwrap/subversion.rb', line 119 def self.remove_force(*args) execute "rm --force #{args.join ' '}" end |
.remove_without_delete(*args) ⇒ Object
Removes the given items from the repository BUT NOT THE DISK. Items may contain wildcards.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/subwrap/subversion.rb', line 124 def self.remove_without_delete(*args) # resolve the wildcards before iterating args.collect {|path| Dir[path]}.flatten.each do |path| entries_file = "#{File.dirname(path)}/.svn/entries" File.chmod(0644, entries_file) xmldoc = REXML::Document.new(IO.read(entries_file)) # first attempt to delete a matching entry with schedule == add unless xmldoc.root.elements.delete "//entry[@name='#{File.basename(path)}'][@schedule='add']" # then attempt to alter a missing schedule to schedule=delete entry = REXML::XPath.first(xmldoc, "//entry[@name='#{File.basename(path)}']") entry.attributes['schedule'] ||= 'delete' if entry end # write back to the file File.open(entries_file, 'w') { |f| xmldoc.write f, 0 } File.chmod(0444, entries_file) end end |
.repository_root(*args) ⇒ Object
405 |
# File 'lib/subwrap/subversion.rb', line 405 def self.repository_root(*args); base_url(*args); end |
.repository_uuid(path_or_url = './') ⇒ Object
408 409 410 411 |
# File 'lib/subwrap/subversion.rb', line 408 def self.repository_uuid(path_or_url = './') matches = info(path_or_url).match(/^Repository UUID: (.+)/) matches && matches[1] end |
.revert(*args) ⇒ Object
Reverts the given items in the working copy. Items may contain wildcards.
145 146 147 |
# File 'lib/subwrap/subversion.rb', line 145 def self.revert(*args) execute "revert #{args.join ' '}" end |
.revision_properties(rev) ⇒ Object
Returns an array of RevisionProperty objects (name, value) for revisions currently set on the given rev
Tessted by: ../../test/subversion_test.rb:test_revision_properties
311 312 313 314 315 |
# File 'lib/subwrap/subversion.rb', line 311 def self.revision_properties(rev) revision_properties_names(rev).map { |property_name| RevisionProperty.new(property_name, get_revision_property(property_name, rev)) } end |
.revision_properties_names(rev) ⇒ Object
Returns an array of the names of all revision properties currently set on the given rev
Tessted by: ../../test/subversion_test.rb:test_revision_properties_names
303 304 305 306 307 308 |
# File 'lib/subwrap/subversion.rb', line 303 def self.revision_properties_names(rev) raw_list = proplist(rev) raw_list.scan(/^ +([^ ]+)$/).map { |matches| matches.first.chomp } end |
.revisions(*args) ⇒ Object
Returns an array of RSCM::Revision objects
354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/subwrap/subversion.rb', line 354 def self.revisions(*args) # Tried using this, but it seems to expect you to pass in a starting date or accept the default starting date of right now, which is silly if you actually just want *all* revisions... #@rscm = ::RSCM::Subversion.new #@rscm.revisions args = (['-v'] + args) log_output = Subversion.log(*args) parser = ::RSCM::SubversionLogParser.new(io = StringIO.new(log_output), url = 'http://ignore.me.com') # :todo: svn revisions -r 747 -- chops off line revisions = parser.parse_revisions revisions end |
.root_url(*args) ⇒ Object
base_url = nil # needed so that base_url variable isn’t local to loop block (and reset during next iteration)!
started_using_dot_dots = false
loop do
matches = /^URL: (.+)/.match(info(path_or_url))
if matches && matches[1]
base_url = matches[1]
else
break base_url
end
# Keep going up the path, one directory at a time, until `svn info` no longer returns a URL (will probably eventually return 'svn: PROPFIND request failed')
if path_or_url.include?('/') && !started_using_dot_dots
path_or_url = File.dirname(path_or_url)
else
started_using_dot_dots = true
path_or_url = File.join(path_or_url, '..')
end
#puts 'going up to ' + path_or_url
end
404 |
# File 'lib/subwrap/subversion.rb', line 404 def self.root_url(*args); base_url(*args); end |
.ruby_script?(file_path) ⇒ Boolean
454 455 456 457 458 459 460 461 |
# File 'lib/subwrap/subversion.rb', line 454 def self.ruby_script?(file_path) if windows_platform? # The 'file' command, we assume, is not available File.readlines(file_path)[0] =~ /ruby/ else `file #{file_path}` =~ /ruby/ end end |
.set_property(property, value, path = './') ⇒ Object
290 291 292 |
# File 'lib/subwrap/subversion.rb', line 290 def self.set_property(property, value, path = './') execute "propset svn:#{property} '#{value}' #{path}" end |
.set_revision_property(property_name, rev) ⇒ Object
293 294 295 |
# File 'lib/subwrap/subversion.rb', line 293 def self.set_revision_property(property_name, rev) execute("propset --revprop #{property_name} -r #{rev}").chomp end |
.status(*args) ⇒ Object
Returns the status of items in the working directories paths
. Returns the raw output from svn (use split("\n")
if you want an array).
162 163 164 165 |
# File 'lib/subwrap/subversion.rb', line 162 def self.status(*args) args = ['./'] if args.empty? execute("status #{args.join ' '}") end |
.status_against_server(*args) ⇒ Object
167 168 169 170 |
# File 'lib/subwrap/subversion.rb', line 167 def self.status_against_server(*args) args = ['./'] if args.empty? self.status('-u', *args) end |
.status_the_section_before_externals(path = './') ⇒ Object
The output from ‘svn status` is nicely divided into two “sections”: the section which pertains to the current working copy (not counting externals as part of the working copy) and then the section with status of all of the externals. This method returns the first section.
185 186 187 188 |
# File 'lib/subwrap/subversion.rb', line 185 def self.status_the_section_before_externals(path = './') status = status(path) || '' status.sub!(/(Performing status.*)/m, '') end |
.under_version_control?(file = './', strict = false) ⇒ Boolean
By default, if you query a directory that is scheduled for addition but hasn’t been committed yet (node doesn’t have a UUID), then we will still return true, because it is scheduled to be under version control. If you want a stricter definition, and only want it to return true if the file exists in the repository (has a UUID)@ then pass strict = true
416 417 418 419 420 421 422 |
# File 'lib/subwrap/subversion.rb', line 416 def self.under_version_control?(file = './', strict = false) if strict !!repository_uuid(file) else # (scheduled_for_addition_counts_as_true) !!url(file) end end |
.unignore(*patterns) ⇒ Object
82 83 84 |
# File 'lib/subwrap/subversion.rb', line 82 def self.unignore(*patterns) raise NotImplementedError end |
.update(*args) ⇒ Object
172 173 174 175 |
# File 'lib/subwrap/subversion.rb', line 172 def self.update(*args) args = ['./'] if args.empty? execute("update #{args.join ' '}") end |
.url(path_or_url = './') ⇒ Object
373 374 375 376 |
# File 'lib/subwrap/subversion.rb', line 373 def self.url(path_or_url = './') matches = info(path_or_url).match(/^URL: (.+)/) matches && matches[1] end |
.working_copy_root(directory = './') ⇒ Object
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
# File 'lib/subwrap/subversion.rb', line 423 def self.working_copy_root(directory = './') uuid = repository_uuid(directory) return nil if uuid.nil? loop do # Keep going up, one level at a time, ... new_directory = File.(File.join(directory, '..')) new_uuid = repository_uuid(new_directory) # Until we get back a uuid that is nil (it's not a working copy at all) or different (you can have a working copy A inside of a different WC B)... break if new_uuid.nil? or new_uuid != uuid directory = new_directory end directory end |