Class: Subversion::SvnCommand
- Defined in:
- lib/subwrap/svn_command.rb,
lib/subwrap/svn_command.rb,
lib/subwrap/svn_command.rb
Defined Under Namespace
Modules: Add, Commit, Copy, Diff, EditMessage, EditRevisionProperty, Externalize, ExternalsItems, GetMessage, Help, Import, LocalIgnore, Log, Mkdir, Move, Revisions, SetMessage, Status, Update, ViewCommits, WhatsNew
Constant Summary collapse
- @@user_preferences =
{}
- @@subcommand_list =
This shouldn’t be necessary. Console::Command should allow introspection. But until such time…
[ 'each_unadded', 'externals_items', 'externals_outline', 'externals_containers', 'edit_externals', 'externalize', 'ignore', 'edit_ignores', 'revisions', 'get_message', 'set_message', 'edit_message', 'view_commits', 'url', 'repository_root', 'working_copy_root', 'repository_uuid', 'latest_revision', 'delete_svn', 'fix_out_of_date_commit_state' ]
Class Method Summary collapse
Instance Method Summary collapse
- #__debug ⇒ Object
- #__dry_run ⇒ Object
-
#__except ⇒ Object
(also: #__exclude)
Usually most Subversion commands are recursive and all-inclusive.
- #__no_color ⇒ Object
- #__print_commands ⇒ Object (also: #__show_commands, #_V, #__Verbose)
- #add(*args) ⇒ Object
-
#add_all_unadded ⇒ Object
—————————————————————————————————————————–.
-
#commit(*args) ⇒ Object
module Commit.
- #copy(*args) ⇒ Object
-
#default ⇒ Object
This is here solely to allow subcommandless commands like ‘svn –version`.
-
#delete_svn(directory = './') ⇒ Object
—————————————————————————————————————————– Cause a working copy to cease being a working copy.
- #diff(*directories) ⇒ Object
-
#each_unadded(*args) ⇒ Object
—————————————————————————————————————————– Goes through each “unadded” file (each file reporting a status of
?
) reported bysvn status
and asks you what you want to do with them (add, delete, or ignore). - #edit_externals(directory = nil) ⇒ Object
-
#edit_ignores(directory = './') ⇒ Object
Example: svn edit_ignores tmp/sessions/.
- #edit_message(directory = './') ⇒ Object
- #edit_property(property_name, directory = './') ⇒ Object
- #edit_revision_property(property_name, directory = './') ⇒ Object
-
#externalize(repo_path, as_arg = nil) ⇒ Object
svn externalize your/repo/shared_tasks/tasks –as shared or svn externalize your/repo/shared_tasks/tasks shared.
-
#externals_containers(directory = "./") ⇒ Object
Lists directories that have the svn:externals property set.
- #externals_items(directory = "./") ⇒ Object
-
#externals_outline(directory = "./") ⇒ Object
For every directory that has the svn:externals property set, this prints out the container name and then lists the contents of its svn:externals property (dir, URL) as a bulleted list.
-
#fix_out_of_date_commit_state(dir) ⇒ Object
A fix for this annoying problem that I seem to come across all too frequentrly: svn: Commit failed (details follow): svn: Your file or directory ‘whatever.rb’ is probably out-of-date.
- #get_message ⇒ Object
- #grep ⇒ Object
- #grep_externals ⇒ Object
- #grep_log ⇒ Object
- #help(subcommand = nil) ⇒ Object
-
#ignore(file) ⇒ Object
—————————————————————————————————————————–.
- #import(*args) ⇒ Object
-
#initialize(*args) ⇒ SvnCommand
constructor
A new instance of SvnCommand.
-
#latest_revision(*args) ⇒ Object
—————————————————————————————————————————–.
- #local_ignore ⇒ Object (also: #dont_commit, #pretend_isnt_versioned)
- #log(*args) ⇒ Object
-
#method_missing(subcommand, *args) ⇒ Object
Any subcommands that we haven’t implemented here will simply be passed on to the built-in svn command.
- #mkdir(*directories) ⇒ Object
- #move(*args) ⇒ Object
- #option_missing(option_name, args) ⇒ Object
-
#repository_root(*args) ⇒ Object
Returns root repository URL for a working copy.
-
#repository_uuid(*args) ⇒ Object
Returns the UUID for a working copy/URL.
-
#revisions(directory = './') ⇒ Object
:todo: what if they pass in 2 filenames?.
- #set_message(new_message) ⇒ Object
- #status(*args) ⇒ Object
-
#under_version_control(*args) ⇒ Object
—————————————————————————————————————————–.
- #update(*args) ⇒ Object
-
#url(*args) ⇒ Object
—————————————————————————————————————————–.
- #view_commits(path = "./") ⇒ Object
- #whats_new ⇒ Object
-
#working_copy_root(*args) ⇒ Object
Returns root/base path for a working copy.
Constructor Details
#initialize(*args) ⇒ SvnCommand
Returns a new instance of SvnCommand.
204 205 206 207 |
# File 'lib/subwrap/svn_command.rb', line 204 def initialize(*args) @passthrough_options = [] super end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(subcommand, *args) ⇒ Object
Any subcommands that we haven’t implemented here will simply be passed on to the built-in svn command. :todo: Distinguish between subcommand_missing and method_missing !
Currently, for example, if as isn't defined, this: puts Subversion.externalize(repo_path, {:as => as })
will call method_missing and try to run `svn as`, which of course will fail (without a sensible relevant error)...
I think we should probably just have a separate subcommand_missing, like we already have a separate option_missing !!!
Even a simple type (sss instead of ss) causes trouble... *this* was causing a call to "/usr/bin/svn new_messsage" -- what huh??
def set_message(new_message = nil)
args << new_messsage if new_message
252 253 254 255 |
# File 'lib/subwrap/svn_command.rb', line 252 def method_missing(subcommand, *args) #puts "method_missing(#{subcommand}, #{args.inspect})" svn :exec, subcommand, *args end |
Class Method Details
.parse_revision_ranges(revisions_array) ⇒ Object
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 |
# File 'lib/subwrap/svn_command.rb', line 941 def SvnCommand.parse_revision_ranges(revisions_array) revisions_array.map do |item| case item when /(\d+):(\d+)/ ($1.to_i .. $2.to_i) when /(\d+)-(\d+)/ ($1.to_i .. $2.to_i) when /(\d+)\.\.(\d+)/ ($1.to_i .. $2.to_i) when /\d+/ item.to_i else raise "Item in revisions_array had an unrecognized format: #{item}" end end. end |
Instance Method Details
#__debug ⇒ Object
216 217 218 |
# File 'lib/subwrap/svn_command.rb', line 216 def __debug $debug = true end |
#__dry_run ⇒ Object
219 220 221 |
# File 'lib/subwrap/svn_command.rb', line 219 def __dry_run Subversion::dry_run = true end |
#__except ⇒ Object Also known as: __exclude
Usually most Subversion commands are recursive and all-inclusive. This option adds file exclusion to most of Subversion’s commands. Use this if you want to commit (/add/etc.) everything but a certain file or set of files
svn commit dir1 dir2 --except dir1/not_ready_yet.rb
234 235 236 237 238 |
# File 'lib/subwrap/svn_command.rb', line 234 def __except # We'll have to use a FileList to do this. This option will remove all file arguments, put them into a FileList as inclusions, # add the exclusions, and then pass the resulting list of files on to the *actual* svn command. # :todo: end |
#__no_color ⇒ Object
213 214 215 |
# File 'lib/subwrap/svn_command.rb', line 213 def __no_color Subversion::color = false end |
#__print_commands ⇒ Object Also known as: __show_commands, _V, __Verbose
223 224 225 |
# File 'lib/subwrap/svn_command.rb', line 223 def __print_commands Subversion::print_commands = true end |
#add(*args) ⇒ Object
308 309 310 311 |
# File 'lib/subwrap/svn_command.rb', line 308 def add(*args) #puts "add #{args.inspect}" svn :exec, 'add', *args end |
#add_all_unadded ⇒ Object
1350 1351 1352 |
# File 'lib/subwrap/svn_command.rb', line 1350 def add_all_unadded raise NotImplementedError end |
#commit(*args) ⇒ Object
module Commit
373 374 375 376 377 378 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 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 |
# File 'lib/subwrap/svn_command.rb', line 373 def commit(*args) directory = args.first || './' # We can only pass one path to .latest_revision and .repository_root, so we'll just arbitrarily choose the first path. They should all be paths within the same repository anyway, so it shouldn't matter. if @broken || @skip_notification latest_rev_before_commit = Subversion.latest_revision(directory) repository_root = Subversion.repository_root(directory) end Subversion.print_commands! do puts svn(:capture, "propset svn:skip_commit_notification_for_next_commit true --revprop -r #{latest_rev_before_commit} #{repository_root}", :prepare_args => false) end if @skip_notification # :todo: # Add some logic to automatically skip the commit e-mail if the size of the files to be committed exceeds a threshold of __ MB. # (Performance idea: Only check the size of the files if svn st includes (bin)?) # Have to use :system rather than :capture because they may not have specified a commit message, in which case it will open up an editor... svn(:system, 'commit', *(['--force-log'] + args)) puts ''.add_exit_code_error return if !exit_code.success? # The following only works if we do :capture (`svn`), but that doesn't work so well (at all) if svn tries to open up an editor (vim), # which is what happens if you don't specify a message.: # puts output = svn(:capture, 'commit', *(['--force-log'] + args)) # just_committed = (matches = output.match(/Committed revision (\d+)\./)) && matches[1] Subversion.print_commands! do puts svn(:capture, "propset code:broken true --revprop -r #{latest_rev_before_commit + 1}", :prepare_args => false) end if @broken if @include_externals #:todo: #externals.each do |external| #svn(:system, 'commit', *(['--force-log'] + args + external)) #end end # This should be disableable! ~/.subwrap ? # http://svn.collab.net/repos/svn/trunk/doc/user/svn-best-practices.html: # After every svn commit, your working copy has mixed revisions. The things you just committed are now at the HEAD revision, and everything else is at an older revision. #puts "Whenever you commit something, strangely, your working copy becomes out of date (as you can observe if you run svn info and look at the revision number). This is a problem for svn log, and piston, to name two applications. So we will now update '#{(args.every + '/..').join(' ').white.bold}' just to make sure they're not out of date..." #print ''.bold # Clear the bold flag that svn annoyingly sets #working_copy_root = Subversion.working_copy_root(directory).to_s #response = confirm("Do you want to update #{working_copy_root.bold} now? (Any key other than y to skip) ") #if response == 'y' #puts "Updating #{working_copy_root} (non-recursively)..." #end #puts Subversion.update_lines_filter( Subversion.update(*args) ) end |
#copy(*args) ⇒ Object
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 |
# File 'lib/subwrap/svn_command.rb', line 722 def copy(*args) destination = args.pop # Unlike the built-in copy, this one lets you list multiple source files # Source... DestinationDir # or # Source Destination # Useful when you have a long list of files you want to copy, such as when you are using wild-cards. Makes commands like this possible: # svn cp source/* dest/ if args.length >= 2 sources = args sources.each do |source| puts filtered_svn('copy', source, destination) end else svn :exec, 'copy', *(args + [destination]) end end |
#default ⇒ Object
This is here solely to allow subcommandless commands like ‘svn –version`
257 258 259 |
# File 'lib/subwrap/svn_command.rb', line 257 def default() svn :exec end |
#delete_svn(directory = './') ⇒ Object
Cause a working copy to cease being a working copy
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 |
# File 'lib/subwrap/svn_command.rb', line 1337 def delete_svn(directory = './') puts "If you continue, all of the following directories/files will be deleted:" system("find #{directory} -name .svn -type d | xargs -n1 echo") response = confirm("Do you wish to continue?") puts if response == 'y' system("find #{directory} -name .svn -type d | xargs -n1 rm -r") end end |
#diff(*directories) ⇒ Object
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
# File 'lib/subwrap/svn_command.rb', line 505 def diff(*directories) directories = ['./'] if directories.empty? puts Subversion.colorized_diff(*(prepare_args(directories))) begin # Show diff for externals (if there *are* any and the user didn't tell us to ignore them) output = StringIO.new #paths = args.reject{|arg| arg =~ /^-/} || ['./'] directories.each do |path| (Subversion.externals_items(path) || []).each do |item| diff_output = Subversion.colorized_diff(item).strip unless diff_output == "" #output.puts '-'*100 #output.puts item.ljust(100, ' ').black_on_white.bold.underline output.puts item.ljust(100).yellow_on_red.bold output.puts diff_output end end end unless output.string == "" #puts '='*100 puts (' '*100).yellow.underline puts " Diff of externals (**don't forget to commit these too!**):".ljust(100, ' ').yellow_on_red.bold.underline puts output.string end end unless @ignore_externals || @non_recursive end |
#each_unadded(*args) ⇒ Object
Goes through each “unadded” file (each file reporting a status of ?
) reported by svn status
and asks you what you want to do with them (add, delete, or ignore)
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 |
# File 'lib/subwrap/svn_command.rb', line 960 def each_unadded(*args) catch :exit do $ignore_dry_run_option = true Subversion.each_unadded( Subversion.status(*args) ) do |file| $ignore_dry_run_option = false begin puts( ('-'*100).green ) puts "What do you want to do with '#{file.white.underline}'?".white.bold begin if !File.exist?(file) raise "#{file} doesn't seem to exist -- even though it was reported by svn status" end if File.file?(file) if FileTest.binary_file?(file) puts "(Binary file -- cannot show preview)".bold else puts "File contents:" # Only show the first x bytes so that we don't accidentally dump the contens of some 20 GB log file to screen... contents = File.read(file, bytes_threshold = 5000) || '' max_lines = 55 contents.lines[0..max_lines].each {|line| puts line} puts "..." if contents.length >= bytes_threshold # So they know that there may be *more* to the file than what's shown end elsif File.directory?(file) puts "Directory contains:" Dir.new(file).reject {|f| ['.','..'].include? f}.each do |f| puts f end else raise "#{file} is not a file or directory -- what *is* it then???" end end print( "Add".(:green) + ", " + "Delete".(:red) + ", " + "add to " + "svn:".yellow + "Ignore".(:yellow) + " property, " + "ignore ".yellow + "Contents".(:yellow) + " of directory, " + "or " + "any other key".white.bold + " to do nothing > " ) response = "" response = $stdin.getch.downcase # while !['a', 'd', 'i', "\n"].include?(begin response.downcase!; response end) case response when 'a' print "\nAdding... " Subversion.add file puts when 'd' puts response = "" if File.directory?(file) response = confirm("Are you pretty much " + "SURE".bold + " you want to '" + "rm -rf #{file}".red.bold + "'? ") else response = "y" end if response == 'y' print "\nDeleting... " FileUtils.rm_rf file puts else puts "\nI figured as much!" end when 'i' print "\nIgnoring... " Subversion.ignore file puts else # Skip / Do nothing with this file puts " (Skipping...)" end rescue Interrupt puts "\nGoodbye!" throw :exit end end # each_unadded end # catch :exit end |
#edit_externals(directory = nil) ⇒ Object
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 |
# File 'lib/subwrap/svn_command.rb', line 1118 def edit_externals(directory = nil) catch :exit do if directory.nil? || !Subversion::ExternalsContainer.new(directory).has_entries? if directory.nil? puts "No directory specified. Editing externals for *all* externals dirs..." directory = "./" else puts "Editing externals for *all* externals dirs..." end Subversion.externals_containers(directory).each do |external| puts external.to_s command = "propedit svn:externals #{external.container_dir}" begin response = confirm("Do you want to edit svn:externals for this directory?".black_on_white) svn :system, command if response == 'y' rescue Interrupt puts "\nGoodbye!" throw :exit ensure puts end end puts 'Done' else #system "#{Subversion.executable} propedit svn:externals #{directory}" svn :system, "propedit svn:externals #{directory}" end end # catch :exit end |
#edit_ignores(directory = './') ⇒ Object
Example:
svn edit_ignores tmp/sessions/
1231 1232 1233 1234 1235 1236 |
# File 'lib/subwrap/svn_command.rb', line 1231 def edit_ignores(directory = './') #puts Subversion.get_property("ignore", directory) # If it's empty, ask them if they want to edit it anyway?? svn :system, "propedit svn:ignore #{directory}" end |
#edit_message(directory = './') ⇒ Object
1328 1329 1330 |
# File 'lib/subwrap/svn_command.rb', line 1328 def (directory = './') edit_revision_property('svn:log', directory) end |
#edit_property(property_name, directory = './') ⇒ Object
1332 1333 |
# File 'lib/subwrap/svn_command.rb', line 1332 def edit_property(property_name, directory = './') end |
#edit_revision_property(property_name, directory = './') ⇒ Object
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 |
# File 'lib/subwrap/svn_command.rb', line 1295 def edit_revision_property(property_name, directory = './') args = ['propedit', '--revprop', property_name, directory] rev = @revision ? @revision : 'head' args.concat ['-r', rev] Subversion.print_commands! do svn :system, *args end value = Subversion::get_revision_property(property_name, rev) p value # Currently there is no seperate option to *delete* a revision property (propdel)... That would be useful for those # properties that are just boolean *flags* (set or not set). # I'm assuming most people will very rarely if ever actually want to set a property to the empty string (''), so # we can use the empty string as a way to trigger a propdel... if value == '' puts response = confirm("Are you sure you want to delete property #{property_name}".red.bold + "'? ") puts if response == 'y' Subversion.print_commands! do Subversion::delete_revision_property(property_name, rev) end end end end |
#externalize(repo_path, as_arg = nil) ⇒ Object
svn externalize your/repo/shared_tasks/tasks –as shared or
svn externalize http://your/repo/shared_tasks/tasks shared
1165 1166 1167 1168 1169 1170 |
# File 'lib/subwrap/svn_command.rb', line 1165 def externalize(repo_path, as_arg = nil) # :todo: let them pass in local_path as well? -- then we would need to accept 2 -- 3 -- args, the first one poylmorphic, the second optional # :todo: automated test for as_arg/as combo Subversion.externalize(repo_path, {:as => as || as_arg}) end |
#externals_containers(directory = "./") ⇒ Object
Lists directories that have the svn:externals property set.
1111 1112 1113 1114 1115 |
# File 'lib/subwrap/svn_command.rb', line 1111 def externals_containers(directory = "./") puts Subversion.externals_containers(directory).map { |external| external.container_dir } end |
#externals_items(directory = "./") ⇒ Object
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 |
# File 'lib/subwrap/svn_command.rb', line 1064 def externals_items(directory = "./") longest_path_name = 25 externals_structs = Subversion.externals_containers(directory).map do |external| returning( external.entries_structs.map do |entry| Struct.new(:path, :repository_path).new( File.join(external.container_dir, entry.name).relativize_path, entry.repository_path ) end ) do |entries_structs| longest_path_name = [ longest_path_name, entries_structs.map { |entry| entry.path.size }.max.to_i ].max end end puts externals_structs.map { |entries_structs| entries_structs.map { |entry| entry.path.ljust(longest_path_name + 1) + (@omit_repository_path ? '' : entry.repository_path) } } puts "(Tip: Also consider using svn externals_outline. Or use the -o/--omit-repository-path option if you just want a list of the paths that are externalled (without the repository URLs that they come from)".magenta unless @omit_repository_path end |
#externals_outline(directory = "./") ⇒ Object
For every directory that has the svn:externals property set, this prints out the container name and then lists the contents of its svn:externals property (dir, URL) as a bulleted list
1102 1103 1104 1105 1106 |
# File 'lib/subwrap/svn_command.rb', line 1102 def externals_outline(directory = "./") puts Subversion.externals_containers(directory).map { |external| external.to_s.relativize_path } end |
#fix_out_of_date_commit_state(dir) ⇒ Object
A fix for this annoying problem that I seem to come across all too frequentrly:
svn: Commit failed (details follow):
svn: Your file or directory 'whatever.rb' is probably out-of-date
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
# File 'lib/subwrap/svn_command.rb', line 430 def fix_out_of_date_commit_state(dir) dir = $1 if dir =~ %r|^(.*)/$| # Strip trailing slash. puts Subversion.export("#{dir}", "#{dir}.new"). # Exports (copies) the contents of working copy 'dir' (including your uncommitted changes, don't worry! ... and you'll get a chance to confirm before anything is deleted; but sometimes although it exports files that are scheduled for addition, they are no longer scheduled for addition in the new working copy, so you have to re-add them) to non-working-copy 'dir.new' add_exit_code_error return if !exit_code.success? system("mv #{dir} #{dir}.backup") # Just in case something goes ary puts ''.add_exit_code_error return if !exit_code.success? puts "Restoring #{dir}..." Subversion.update dir # Restore the directory to a pristine state so we will no longer get that annoying error # Assure the user that dir.new really does have your latest changes #puts "Here's a diff. Your changes/additions will be in the *right* (>) file." #system("diff #{dir}.backup #{dir}") # Merge those latest changes back into the pristine working copy system("cp -R #{dir}.new/. #{dir}/") # Assure the user one more time puts Subversion.colorized_diff(dir) puts "Please check the output of " + "svn st #{dir}.backup".blue.bold + " to check if any files were scheduled for addition. You will need to manually re-add these, as the export will have caused those files to lost their scheduling." Subversion.print_commands! do print Subversion.status_lines_filter( Subversion.status("#{dir}.backup") ) print Subversion.status_lines_filter( Subversion.status("#{dir}") ) end # Actually commit puts response = confirm("Are you ready to try the commit again now?") puts if response == 'y' puts "Great! Go for it. (I'd do it for you but I don't know what commit command you were trying to execute when the problem occurred.)" end # Clean up #puts #response = confirm("Do you want to delete array.backup array.new now?") puts "Don't forget to " + "rm -rf #{dir}.backup #{dir}.new".blue.bold + " when you are done!" #rm_rf array.backup, array.new puts end |
#get_message ⇒ Object
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 |
# File 'lib/subwrap/svn_command.rb', line 1248 def () #svn propget --revprop svn:log -r2325 args = ['propget', '--revprop', 'svn:log'] #args.concat ['-r', @revision ? @revision : Subversion.latest_revision] args.concat ['-r', (revision = @revision ? @revision : 'head')] puts "Message for r#{Subversion.latest_revision} :" if revision == 'head' $ignore_dry_run_option = true puts filtered_svn(*args) $ignore_dry_run_option = false end |
#grep ⇒ Object
1353 1354 1355 |
# File 'lib/subwrap/svn_command.rb', line 1353 def grep raise NotImplementedError end |
#grep_externals ⇒ Object
1356 1357 1358 |
# File 'lib/subwrap/svn_command.rb', line 1356 def grep_externals raise NotImplementedError end |
#grep_log ⇒ Object
1359 1360 1361 |
# File 'lib/subwrap/svn_command.rb', line 1359 def grep_log raise NotImplementedError end |
#help(subcommand = nil) ⇒ Object
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 |
# File 'lib/subwrap/svn_command.rb', line 540 def help(subcommand = nil) case subcommand when "externals" puts %Q{ | externals (ext): Lists all externals in the given working directory. | usage: externals [PATH] }.margin # :todo: Finish... when nil puts "You are using " + 's'.green.bold + 'u'.cyan.bold + 'b'.magenta.bold + 'w'.white.bold + 'r'.red.bold + 'a'.blue.bold + 'p'.yellow.bold + ' version ' + Project::Version ", a colorful, useful replacement/wrapper for the standard svn command." puts "subwrap is installed at: " + $0.bold puts "You may bypass this wrapper by using the full path to svn: " + Subversion.executable.bold puts puts Subversion.help(subcommand).gsub(<<End, '') Subversion is a tool for version control. For additional information, see http://subversion.tigris.org/ End puts puts 'Subcommands added by subwrap (refer to '.green.underline + 'http://subwrap.rubyforge.org/'.white.underline + ' for usage details):'.green.underline @@subcommand_list.each do |subcommand| aliases_list = subcommand_aliases_list(subcommand.option_methodize.to_sym) aliases_list = aliases_list.empty? ? '' : ' (' + aliases_list.join(', ') + ')' puts ' ' + subcommand + aliases_list end #p subcommand_aliases_list(:edit_externals) else #puts "help #{subcommand}" puts Subversion.help(subcommand) end end |
#ignore(file) ⇒ Object
1225 1226 1227 |
# File 'lib/subwrap/svn_command.rb', line 1225 def ignore(file) Subversion.ignore(file) end |
#import(*args) ⇒ Object
755 756 757 758 |
# File 'lib/subwrap/svn_command.rb', line 755 def import(*args) p args svn :exec, 'import', *(args) end |
#latest_revision(*args) ⇒ Object
896 897 898 |
# File 'lib/subwrap/svn_command.rb', line 896 def latest_revision(*args) puts Subversion.latest_revision end |
#local_ignore ⇒ Object Also known as: dont_commit, pretend_isnt_versioned
1217 1218 1219 |
# File 'lib/subwrap/svn_command.rb', line 1217 def local_ignore #... end |
#log(*args) ⇒ Object
591 592 593 594 |
# File 'lib/subwrap/svn_command.rb', line 591 def log(*args) puts Subversion.log( prepare_args(args) ) #svn :exec, *args end |
#mkdir(*directories) ⇒ Object
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 |
# File 'lib/subwrap/svn_command.rb', line 613 def mkdir(*directories) if @create_parents directories.each do |directory| # :todo: change this so that it's guaranteed to have an exit condition; currently, can get into infinite loop loop do puts "Creating '#{directory}'" FileUtils.mkdir_p directory # Create it if it doesn't already exist if Subversion.under_version_control?(File.dirname(directory)) # Yay, we found a working copy. Now we can issue an add command, from that directory, which will recursively add the # (non-working copy) directories we've been creating along the way. #puts Subversion.add prepare_args([directory]) svn :system, 'add', *directory break else directory = File.dirname(directory) end end end else # Preserve default behavior. svn :system, 'mkdir', *directories end end |
#move(*args) ⇒ Object
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 |
# File 'lib/subwrap/svn_command.rb', line 661 def move(*args) destination = args.pop # If the last character is a '/', then they obviously expect the destination to be a *directory*. Yet when I do this: # svn mv a b/ # and b doesn't exist, # it moves a (a file) to b as a file, rather than creating directory b/ and moving a to b/a. # I find this default behavior less than intuitive, so I have "fixed" it here... # So instead of seeing this: # A b # D a # You should see this: # A b # A b/a # D a if destination[-1..-1] == '/' if !File.exist?(destination[0..-2]) puts "Notice: It appears that the '" + destination.bold + "' directory doesn't exist. Would you like to create it now? Good..." self.mkdir destination # @create_parents flag will be reused there elsif !File.directory?(destination[0..-2]) puts "Error".red.bold + ": It appears that '" + destination.bold + "' already exists but is not actually a directory. " + "The " + 'destination'.bold + " must either be the path to a " + 'file'.underline + " that does " + 'not'.underline + " yet exist or the path to a " + 'directory'.underline + " (which may or may not yet exist)." return end end if @create_parents and !Subversion.under_version_control?(destination_dir = File.dirname(destination)) puts "Creating parent directory '#{destination_dir}'..." self.mkdir destination_dir # @create_parents flag will be reused there end # Unlike the built-in move, this one lets you list multiple source files # Source... DestinationDir # or # Source Destination # Useful when you have a long list of files you want to move, such as when you are using wild-cards. Makes commands like this possible: # svn mv source/* dest/ if args.length >= 2 sources = args sources.each do |source| puts filtered_svn('move', source, destination) end else svn :exec, 'move', *(args + [destination]) end end |
#option_missing(option_name, args) ⇒ Object
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/subwrap/svn_command.rb', line 261 def option_missing(option_name, args) #puts "#{@subcommand} defined? #{@subcommand_is_defined}" if !@subcommand_is_defined # It's okay to use this for pass-through subcommands, because we just pass all options/arguments verbatim anyway... #puts "option_missing(#{option_name}, #{args.inspect})" else # But for subcommands that are defined here, we should know better! All valid options should be explicitly listed! raise UnknownOptionError.new(option_name) end # The following is necessary because we really don't know the arity (how many subsequent tokens it should eat) of the option -- we don't know anything about the options, in fact; that's why we've landed in option_missing. # This is kind of a hokey solution, but for any unrecognized options/args (which will be *all* of them unless we list the available options in the subcommand module), we just eat all of the args, store them in @passthrough_options, and later we will add them back on. # What's annoying about it this solution is that *everything* after the first unrecognized option comes in as args, even if they are args for the subcommand and not for the *option*! # But...it seems to work to just pretend they're options. # It seems like this is mostly a problem for *wrappers* that try to use Console::Command. Sometimes you just want to *pass through all args and options* unchanged and just filter the output somehow. # Command doesn't make that super-easy though. If an option (--whatever) isn't defined, then the only way to catch it is in option_missing. And since we can't the arity unless we enumerate all options, we have to hokily treat the first option as having unlimited arity. # Alternatives considered: # * Assume arity of 0. Then I'm afraid it would extract out all the option flags and leave the args that were meant for the args dangling there out of order ("-r 1 -m 'hi'" => "-r -m", "1 'hi'") # * Assume arity of 1. Then if it was really 0, it would pick up an extra arg that really wasn't supposed to be an arg for the *option*. # Ideally, we wouldn't be using option_missing at all because all options would be listed in the respective subcommand module...but for subcommands handled through method_missing, we don't have that option. # The args will look like this, for example: # option_missing(-m, ["a multi-word message", "--something-else", "something else"]) # , so we need to be sure we wrap multi-word args in quotes as necessary. That's what the args.shell_escape does. @passthrough_options << "#{option_name}" << args.shell_escape @passthrough_options.flatten! # necessary now that we have args.shell_escape ? return arity = args.size # All of 'em end |
#repository_root(*args) ⇒ Object
Returns root repository URL for a working copy
889 890 891 |
# File 'lib/subwrap/svn_command.rb', line 889 def repository_root(*args) puts Subversion.repository_root(*args) end |
#repository_uuid(*args) ⇒ Object
Returns the UUID for a working copy/URL
883 884 885 |
# File 'lib/subwrap/svn_command.rb', line 883 def repository_uuid(*args) puts Subversion.repository_uuid(*args) end |
#revisions(directory = './') ⇒ Object
:todo: what if they pass in 2 filenames?
1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 |
# File 'lib/subwrap/svn_command.rb', line 1500 def revisions(directory = './') puts "Getting list of revisions for '#{directory.white.bold}' ..." #----------------------------- head = Subversion.latest_revision revision_of_directory = Subversion.latest_revision_for_path(directory) # It's possible for a working copy to get "out of date" (even if you were the last committer! at least, each *directory* seems to have a different concept of base rev), in which case svn log will # only list revisions up to that revision (actually looks like it only goes up to and including Last Changed Rev: 2838, # not Revision: 2839, as reported by svn info...) if revision_of_directory and head and revision_of_directory < head puts "The working copy '#{directory.white.bold}' appears to be out-of-date (#{revision_of_directory}) with respect to the head revision (#{head}). Updating..." Subversion.update(directory) end #----------------------------- args = [directory] #@revisions ||= '1:head' # this was messing with --limit 5, making it start at 1 instead of most recent if @revisions @revisions.gsub! /%base%/, revision_of_directory args.concat ['-r', @revisions] end @newest_first_default.nil? ? @newest_first_default = false : nil @newest_first.nil? ? @newest_first = @newest_first_default : nil @show_diffs ||= true if !@interactive @show_diffs_default ||= false @show_diffs ||= @show_diffs_default if @show_file_list.nil? if directory != './' # They specified a (non-default) directory/file @show_file_list = false else @show_file_list = true end end run_pager if !@interactive #----------------------------- #pp prepare_args(args) revisions = Subversion.revisions(*prepare_args(args)) #puts "@newest_first=#{@newest_first}" puts "#{revisions.length.to_s.bold} revisions found. Starting with #{(@newest_first ? 'most recent' : 'oldest').green.bold} revision and #{@newest_first ? 'going backward in time' :'going forward in time' }..." revisions.instance_variable_get(:@revisions).reverse! if @newest_first revision_ids = revisions.map(&:identifier) #----------------------------------------------------------------------- # The main loop through the array of revisions target_rev = nil # revision_ids.first show_revision = true revisions.each do |revision| rev = revision.identifier other_rev = rev-1 if target_rev if rev == target_rev target_rev = nil # We have arrived. else next # Keep going (hopefully in the right direction!) end end #----------------------------------------------------------------------- show_diffs = proc { revs_to_compare = [other_rev, rev] #puts "\n"*10 puts puts((' '*100).green.underline) print "Diffing #{revs_to_compare.min}:#{revs_to_compare.max}... ".bold puts #Subversion.repository_root #Subversion.print_commands! do SvnCommand.execute("diff #{directory} --ignore-externals -r #{revs_to_compare.min}:#{revs_to_compare.max}") #end } #----------------------------------------------------------------------- # Display the revision (number, date, description, files changed) if show_revision #puts((' '*100).green.underline) puts puts((' '*100).on_green) puts "#{revisions.length - revision_ids.index(rev)}. ".green.bold + "r#{rev}".magenta.bold + (rev == head ? ' (head)'.bold : '') + " | #{revision.developer} | #{revision.time.strftime('%Y-%m-%d %H:%M:%S')}".magenta.bold puts revision. puts #pp revision if @show_file_list puts revision.map {|a| (a.status ? a.status[0..0].colorize_svn_status_code : ' ') + # This check is necessary because RSCM doesn't recognize several Subversion status flags, including 'R', and status will return nil in these cases. ' ' + a.path }.join("\n") end else show_revision = true end #----------------------------------------------------------------------- if @show_diffs show_diffs.call end #----------------------------------------------------------------------- # Display the menu if @interactive print( "r#{rev}".magenta.on_blue.bold + ': ' + 'View this changeset'.(:cyan) + ', ' + 'Diff against specific revision'.(:cyan, 'D') + ', ' + 'Grep the changeset'.(:cyan, 'G') + ', ' + 'List or '.(:magenta, 'L') + '' + 'Edit revision properties'.(:magenta, 'E') + ', ' + 'svn Cat all files'.(:cyan, 'C') + ', ' + 'grep the cat'.(:cyan, 'a') + ', ' + "\n " + 'mark as Reviewed'.(:green, 'R') + ', ' + 'edit log Message'.(:yellow, 'M') + ', ' + 'or ' + 'browse using ' + 'Up/Down/Space/Enter'.white.bold + ' keys > ' ) end #----------------------------------------------------------------------- # Get response from user and then act on it begin # rescue if @interactive response = "" response = $stdin.getch.downcase else response = "\n" end # Escape sequence such as the up arrow key ("\e[A") if response == "\e" response << (next_char = $stdin.getch) if next_char == '[' response << (next_char = $stdin.getch) end end if response == 'd' # diff against Other revision response = 'v' puts print 'All right, which revision shall it be then? '.bold + ' (backspace not currently supported)? ' other_rev = $stdin.gets.chomp.to_i end case response when '1', 'v' # View this changeset show_diffs.call show_revision = false # only show the menu when 'g' # Grep the changeset # :todo; make it accept regexpes like /like.*this/im so you can make it case insensitive or multi-line revs_to_compare = [other_rev, rev] puts print 'Grep for'.bold + ' (Case sensitive; Regular expressions ' + 'like.*this'.bold.blue + ' allowed, but not ' + '/like.*this/im'.bold.blue + ') (backspace not currently supported): ' search_pattern = $stdin.gets.chomp.to_rx puts((' '*100).green.underline) puts "Searching `svn diff #{directory} -r #{revs_to_compare.min}:#{revs_to_compare.max}` for #{search_pattern.to_s}... ".bold diffs = nil #Subversion.print_commands! do diffs = Subversion.diffs(directory, '-r', "#{revs_to_compare.min}:#{revs_to_compare.max}") #end hits = 0 diffs.each do |filename, diff| #.grep(search_pattern) if diff.diff =~ search_pattern puts diff.filename_pretty puts( diff.diff.grep(search_pattern). # This will get us just the interesting *lines* (as an array). map { |line| # Now, for each line... hits += 1 line.highlight_occurences(search_pattern) } ) end end if hits == 0 puts "Search term not found!".red.bold end show_revision = false when 'a' # Grep the cat puts print 'Grep for'.bold + ' (Case sensitive; Regular expressions ' + 'like.*this'.bold.blue + ' allowed, but not ' + '/like.*this/im'.bold.blue + ') (backspace not currently supported): ' search_pattern = $stdin.gets.chomp.to_rx puts((' '*100).green.underline) puts "Searching `svn cat #{directory} -r #{rev}` for #{search_pattern.to_s}... ".bold contents = nil Subversion.print_commands! do contents = Subversion.cat(directory, '-r', rev) end if contents =~ search_pattern puts( contents.grep(search_pattern). # This will get us just the interesting *lines* (as an array). map { |line| # Now, for each line... line.highlight_occurences(search_pattern) } ) else puts "Search term not found!".red.bold end show_revision = false when 'l' # List revision properties puts puts Subversion::printable_revision_properties(rev) show_revision = false when 'e' # Edit revision property puts puts Subversion::printable_revision_properties(rev) puts "Warning: These properties are *not* under version control! Try not to permanently destroy anything *too* important...".red.bold puts "Note: If you want to *delete* a property, simply set its value to '' and it will be deleted (propdel) for you." print 'Which property would you like to edit'.bold + ' (backspace not currently supported)? ' property_name = $stdin.gets.chomp unless property_name == '' Subversion.print_commands! do @revision = rev edit_revision_property(property_name, directory) end end show_revision = false when 'c' # Cat all files from revision puts Subversion.print_commands! do puts Subversion.cat(directory, '-r', rev) end show_revision = true when 'r' # Mark as reviewed puts your_name = ENV['USER'] # I would use the same username that Subversion itself would use if you committed # something (since it is sometimes different from your system username), but I don't know # how to retrieve that (except by poking around in your ~/.subversion/ directory, but # that seems kind of rude...). puts "Marking as reviewed by '#{your_name}'..." Subversion.print_commands! do puts svn(:capture, "propset code:reviewed '#{your_name}' --revprop -r #{rev}", :prepare_args => false) # :todo: Maybe *append* to code:reviewed (,-delimited) rather than overwriting it?, in case there is a policy of requiring 2 reviewers or something end show_revision = false when 'm' # Edit log message puts Subversion.print_commands! do SvnCommand.execute("edit_message -r #{rev}") end show_revision = false when "\e[A" # Up i = revision_ids.index(rev) target_rev = revision_ids[i - 1] puts " Previous..." retry when /\n|\e\[B| / # Enter or Down or Space # Skip / Do nothing with this file puts " Next..." #show_revision = false #? next else # Invalid option. Do nothing. #puts response.inspect puts show_revision = false end # case response redo # Until they tell us they're ready to move on... rescue Interrupt puts "\nGoodbye!" return end # rescue end end |
#set_message(new_message) ⇒ Object
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 |
# File 'lib/subwrap/svn_command.rb', line 1270 def () #svn propset --revprop -r 25 svn:log "Journaled about trip to New York." puts "Message before changing:" args = ['propset', '--revprop', 'svn:log'] args.concat ['-r', @revision ? @revision : 'head'] args << if if @filename contents = File.readlines(@filename).join.strip puts "Read file '#{@filename}':" print contents puts args << contents end svn :exec, *args end |
#status(*args) ⇒ Object
806 807 808 809 810 811 |
# File 'lib/subwrap/svn_command.rb', line 806 def status(*args) = {} [:only_statuses] = @only_statuses [:files_only] = @files_only print Subversion.status_lines_filter( Subversion.status(*(prepare_args(args))), ) end |
#under_version_control(*args) ⇒ Object
871 872 873 |
# File 'lib/subwrap/svn_command.rb', line 871 def under_version_control(*args) puts Subversion.under_version_control?(*args) end |
#update(*args) ⇒ Object
845 846 847 848 849 850 |
# File 'lib/subwrap/svn_command.rb', line 845 def update(*args) @passthrough_options << '--ignore-externals' if ignore_externals? Subversion.print_commands! do # Print the commands and options used so they can be reminded that they're using user_preferences['update']['ignore_externals']... puts Subversion.update_lines_filter( Subversion.update(*prepare_args(args)) ) end end |
#url(*args) ⇒ Object
865 866 867 |
# File 'lib/subwrap/svn_command.rb', line 865 def url(*args) puts Subversion.url(*args) end |
#view_commits(path = "./") ⇒ Object
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 |
# File 'lib/subwrap/svn_command.rb', line 922 def view_commits(path = "./") if @revisions.nil? raise "-r (revisions) option is mandatory" end $ignore_dry_run_option = true base_url = Subversion.base_url(path) $ignore_dry_run_option = false #puts "Base URL: #{base_url}" revisions = self.class.parse_revision_ranges(@revisions) revisions.each do |revision| puts Subversion.log("-r #{revision} -v #{base_url}") end puts Subversion.diff("-r #{revisions.first}:#{revisions.last} #{path}") #/usr/bin/svn diff http://code.qualitysmith.com/gemables/subversion@2279 http://code.qualitysmith.com/gemables/subwrap@2349 --diff-cmd colordiff end |
#whats_new ⇒ Object
1369 1370 1371 |
# File 'lib/subwrap/svn_command.rb', line 1369 def whats_new SvnCommand.execute("revisions --whats-new --non-interactive") end |
#working_copy_root(*args) ⇒ Object
Returns root/base path for a working copy
877 878 879 |
# File 'lib/subwrap/svn_command.rb', line 877 def working_copy_root(*args) puts Subversion.working_copy_root(*args) end |