Module: Subversion
- Extended by:
- Extensions
- Defined in:
- lib/svn-command/subversion.rb,
lib/svn-command/subversion.rb,
lib/svn-command/svn_command.rb,
lib/svn-command/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: 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
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.
- .delete_property(property, path = './') ⇒ Object
- .delete_revision_property(property_name, rev) ⇒ Object
-
.diff(*args) ⇒ Object
Returns the local modifications to the working directory specified by
path
. -
.executable ⇒ Object
The location of the executable to be used.
-
.externalize(repo_url, options = {}) ⇒ Object
Adds the given repo 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(*args) ⇒ Object
Returns the revision number for head.
-
.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
- .print_commands_for(&block) ⇒ 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
-
.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
Tested 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
Tested by: ../../test/subversion_test.rb:test_revision_properties_names. -
.revisions(*args) ⇒ Object
Returns an array of RSCM::Revision objects.
- .root_url(*args) ⇒ Object
- .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.
- .unignore(*patterns) ⇒ Object
- .update(*args) ⇒ Object
Methods included from Extensions
each_unadded, printable_revision_properties, status_lines_filter, unadded_filter, unadded_lines_filter, update_lines_filter
Class Method Details
.add(*args) ⇒ Object
Adds the given items to the repository. Items may contain wildcards.
45 46 47 |
# File 'lib/svn-command/subversion.rb', line 45 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?)
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/svn-command/subversion.rb', line 192 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
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/svn-command/subversion.rb', line 291 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 # 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 |
.delete_property(property, path = './') ⇒ Object
217 218 219 |
# File 'lib/svn-command/subversion.rb', line 217 def self.delete_property(property, path = './') execute "propdel svn:#{property} #{path}" end |
.delete_revision_property(property_name, rev) ⇒ Object
220 221 222 |
# File 'lib/svn-command/subversion.rb', line 220 def self.delete_revision_property(property_name, rev) execute("propdel --revprop #{property_name} -r #{rev}").chomp end |
.diff(*args) ⇒ Object
Returns the local modifications to the working directory specified by path
.
184 185 186 187 188 |
# File 'lib/svn-command/subversion.rb', line 184 def self.diff(*args) args = ['./'] if args.empty? #puts("diff #{"--diff-cmd colordiff" if color} #{args.join ' '}") execute("diff #{"--diff-cmd colordiff" if color} #{args.join ' '}") end |
.executable ⇒ Object
The location of the executable to be used
320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/svn-command/subversion.rb', line 320 def self.executable @@executable ||= ENV['PATH'].split(':').each do |dir| # if File.exist?(executable = "#{dir}/svn") # puts executable # end if File.exist?(executable = "#{dir}/svn") and # `file #{executable}` !~ /ruby/ # We want to wrap the svn command provided by Subversion, not our custom replacement for that. return executable end end # end |
.externalize(repo_url, options = {}) ⇒ Object
Adds the given repo 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 ‘./’
74 75 76 77 78 79 |
# File 'lib/svn-command/subversion.rb', line 74 def self.externalize(repo_url, = {}) [:local_path] ||= './' [:as] ||= File.basename(repo_url) [:as] = [:as].ljust(29) 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
.
172 173 174 175 176 177 178 179 180 181 |
# File 'lib/svn-command/subversion.rb', line 172 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’.
159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/svn-command/subversion.rb', line 159 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?
210 211 212 |
# File 'lib/svn-command/subversion.rb', line 210 def self.get_property(property, path = './') execute "propget svn:#{property} #{path}" end |
.get_revision_property(property_name, rev) ⇒ Object
213 214 215 |
# File 'lib/svn-command/subversion.rb', line 213 def self.get_revision_property(property_name, rev) execute("propget --revprop #{property_name} -r #{rev}").chomp end |
.help(*args) ⇒ Object
255 256 257 |
# File 'lib/svn-command/subversion.rb', line 255 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.
54 55 56 57 58 59 60 61 62 63 |
# File 'lib/svn-command/subversion.rb', line 54 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
285 286 287 288 |
# File 'lib/svn-command/subversion.rb', line 285 def self.info(*args) args = ['./'] if args.empty? execute "info #{args.join(' ')}" end |
.latest_revision(*args) ⇒ Object
Returns the revision number for head.
265 266 267 268 269 |
# File 'lib/svn-command/subversion.rb', line 265 def self.latest_revision(*args) args = ['./'] if args.empty? matches = /Status against revision:\s+(\d+)/m.match(status_against_server(args)) matches && matches[1] end |
.log(*args) ⇒ Object
Returns the raw output from svn log
260 261 262 263 |
# File 'lib/svn-command/subversion.rb', line 260 def self.log(*args) args = ['./'] if args.empty? execute "log #{args.join(' ')}" end |
.make_directory(dir) ⇒ Object
251 252 253 |
# File 'lib/svn-command/subversion.rb', line 251 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.
119 120 121 122 123 |
# File 'lib/svn-command/subversion.rb', line 119 def self.make_executable(*paths) paths.each do |path| self.set_property 'executable', '', path end end |
.make_not_executable(*paths) ⇒ Object
124 125 126 127 128 |
# File 'lib/svn-command/subversion.rb', line 124 def self.make_not_executable(*paths) paths.each do |path| self.delete_property 'executable', path end end |
.print_commands_for(&block) ⇒ Object
334 335 336 337 338 |
# File 'lib/svn-command/subversion.rb', line 334 def self.print_commands_for(&block) old_print_commands, @@print_commands = @@print_commands, true yield @@print_commands = old_print_commands end |
.proplist(rev) ⇒ Object
Gets raw output of proplist command
232 233 234 |
# File 'lib/svn-command/subversion.rb', line 232 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.
82 83 84 |
# File 'lib/svn-command/subversion.rb', line 82 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
88 89 90 |
# File 'lib/svn-command/subversion.rb', line 88 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.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/svn-command/subversion.rb', line 93 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
317 |
# File 'lib/svn-command/subversion.rb', line 317 def self.repository_root(*args); base_url(*args); end |
.revert(*args) ⇒ Object
Reverts the given items in the working copy. Items may contain wildcards.
114 115 116 |
# File 'lib/svn-command/subversion.rb', line 114 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
Tested by: ../../test/subversion_test.rb:test_revision_properties
245 246 247 248 249 |
# File 'lib/svn-command/subversion.rb', line 245 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
Tested by: ../../test/subversion_test.rb:test_revision_properties_names
237 238 239 240 241 242 |
# File 'lib/svn-command/subversion.rb', line 237 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
272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/svn-command/subversion.rb', line 272 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 #log_output = Subversion.log('-v') log_output = Subversion.log(*(['-v'] + args)) parser = ::RSCM::SubversionLogParser.new(io = StringIO.new(log_output), url = 'http://ignore.me.com') 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
316 |
# File 'lib/svn-command/subversion.rb', line 316 def self.root_url(*args); base_url(*args); end |
.set_property(property, value, path = './') ⇒ Object
224 225 226 |
# File 'lib/svn-command/subversion.rb', line 224 def self.set_property(property, value, path = './') execute "propset svn:#{property} '#{value}' #{path}" end |
.set_revision_property(property_name, rev) ⇒ Object
227 228 229 |
# File 'lib/svn-command/subversion.rb', line 227 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).
131 132 133 134 |
# File 'lib/svn-command/subversion.rb', line 131 def self.status(*args) args = ['./'] if args.empty? execute("status #{args.join ' '}") end |
.status_against_server(*args) ⇒ Object
136 137 138 139 |
# File 'lib/svn-command/subversion.rb', line 136 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.
149 150 151 152 |
# File 'lib/svn-command/subversion.rb', line 149 def self.status_the_section_before_externals(path = './') status = status(path) || '' status.sub!(/(Performing status.*)/m, '') end |
.unignore(*patterns) ⇒ Object
64 65 66 |
# File 'lib/svn-command/subversion.rb', line 64 def self.unignore(*patterns) raise NotImplementedError end |
.update(*args) ⇒ Object
141 142 143 144 |
# File 'lib/svn-command/subversion.rb', line 141 def self.update(*args) args = ['./'] if args.empty? execute("update #{args.join ' '}") end |