Class: Subversion::SvnCommand
- Defined in:
- lib/svn-command/svn_command.rb,
lib/svn-command/svn_command.rb,
lib/svn-command/svn_command.rb
Defined Under Namespace
Modules: Add, Commit, Copy, Diff, EditMessage, EditRevisionProperty, Externalize, ExternalsItems, GetMessage, Help, Import, Log, Mkdir, Move, Revisions, SetMessage, Status, Update, ViewCommits
Constant Summary collapse
- C_standard_remote_command_options =
Constants
{ [:__username] => 1, [:__password] => 1, [:__no_auth_cache] => 0, [:__non_interactive] => 0, [:__config_dir] => 1, }
- C_standard_commitable_command_options =
{ [:_m, :__message] => 1, [:_F, :__file] => 1, [:__force_log] => 0, [:__editor_cmd] => 1, [:__encoding] => 1, }
- @@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
—————————————————————————————————————————–.
- #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
- #set_message(new_message) ⇒ Object
- #status(*args) ⇒ Object
-
#under_version_control(*args) ⇒ Object
—————————————————————————————————————————–.
- #update(*args) ⇒ Object
-
#url(*args) ⇒ Object
—————————————————————————————————————————–.
- #view_commits(path = "./") ⇒ 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.
193 194 195 196 |
# File 'lib/svn-command/svn_command.rb', line 193 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
241 242 243 244 |
# File 'lib/svn-command/svn_command.rb', line 241 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
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 |
# File 'lib/svn-command/svn_command.rb', line 894 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
205 206 207 |
# File 'lib/svn-command/svn_command.rb', line 205 def __debug $debug = true end |
#__dry_run ⇒ Object
208 209 210 |
# File 'lib/svn-command/svn_command.rb', line 208 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
223 224 225 226 227 |
# File 'lib/svn-command/svn_command.rb', line 223 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
202 203 204 |
# File 'lib/svn-command/svn_command.rb', line 202 def __no_color Subversion::color = false end |
#__print_commands ⇒ Object Also known as: __show_commands, _V, __Verbose
212 213 214 |
# File 'lib/svn-command/svn_command.rb', line 212 def __print_commands Subversion::print_commands = true end |
#add(*args) ⇒ Object
297 298 299 300 |
# File 'lib/svn-command/svn_command.rb', line 297 def add(*args) #puts "add #{args.inspect}" svn :exec, 'add', *args end |
#add_all_unadded ⇒ Object
1247 1248 1249 |
# File 'lib/svn-command/svn_command.rb', line 1247 def add_all_unadded raise NotImplementedError end |
#commit(*args) ⇒ Object
module Commit
362 363 364 365 366 367 368 369 370 371 372 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 |
# File 'lib/svn-command/svn_command.rb', line 362 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! ~/.svn-command ? # 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
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 |
# File 'lib/svn-command/svn_command.rb', line 710 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`
246 247 248 |
# File 'lib/svn-command/svn_command.rb', line 246 def default() svn :exec end |
#delete_svn(directory = './') ⇒ Object
Cause a working copy to cease being a working copy
1235 1236 1237 1238 1239 1240 1241 1242 1243 |
# File 'lib/svn-command/svn_command.rb', line 1235 def delete_svn(directory = './') puts "If you continue, all of the following directories/files will be deleted:" system("find #{directory} -name .svn | xargs -n1 echo") response = confirm("Do you wish to continue?") puts if response == 'y' system("find #{directory} -name .svn | xargs -n1 rm -r") end end |
#diff(*directories) ⇒ Object
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
# File 'lib/svn-command/svn_command.rb', line 493 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)
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 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 |
# File 'lib/svn-command/svn_command.rb', line 913 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
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 |
# File 'lib/svn-command/svn_command.rb', line 1071 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/
1134 1135 1136 1137 1138 1139 |
# File 'lib/svn-command/svn_command.rb', line 1134 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
1226 1227 1228 |
# File 'lib/svn-command/svn_command.rb', line 1226 def (directory = './') edit_revision_property('svn:log', directory) end |
#edit_property(property_name, directory = './') ⇒ Object
1230 1231 |
# File 'lib/svn-command/svn_command.rb', line 1230 def edit_property(property_name, directory = './') end |
#edit_revision_property(property_name, directory = './') ⇒ Object
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 |
# File 'lib/svn-command/svn_command.rb', line 1193 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
1118 1119 1120 1121 1122 1123 |
# File 'lib/svn-command/svn_command.rb', line 1118 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.
1064 1065 1066 1067 1068 |
# File 'lib/svn-command/svn_command.rb', line 1064 def externals_containers(directory = "./") puts Subversion.externals_containers(directory).map { |external| external.container_dir } end |
#externals_items(directory = "./") ⇒ Object
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 |
# File 'lib/svn-command/svn_command.rb', line 1017 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
1055 1056 1057 1058 1059 |
# File 'lib/svn-command/svn_command.rb', line 1055 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
419 420 421 422 423 424 425 426 427 428 429 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 |
# File 'lib/svn-command/svn_command.rb', line 419 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
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 |
# File 'lib/svn-command/svn_command.rb', line 1149 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
1250 1251 1252 |
# File 'lib/svn-command/svn_command.rb', line 1250 def grep raise NotImplementedError end |
#grep_externals ⇒ Object
1253 1254 1255 |
# File 'lib/svn-command/svn_command.rb', line 1253 def grep_externals raise NotImplementedError end |
#grep_log ⇒ Object
1256 1257 1258 |
# File 'lib/svn-command/svn_command.rb', line 1256 def grep_log raise NotImplementedError end |
#help(subcommand = nil) ⇒ Object
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
# File 'lib/svn-command/svn_command.rb', line 528 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 + 'v'.cyan.bold + 'n'.magenta.bold + '-' + 'c'.red.bold + 'o'.cyan.bold + 'm'.blue.bold + 'm'.yellow.bold + 'a'.green.bold + 'n'.white.bold + 'd'.green.bold + ' version ' + Project::Version ", a colorful, useful replacement/wrapper for the standard svn command." puts "svn-command 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 svn-command (refer to '.green.underline + 'http://svn-command.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
1128 1129 1130 |
# File 'lib/svn-command/svn_command.rb', line 1128 def ignore(file) Subversion.ignore(file) end |
#import(*args) ⇒ Object
743 744 745 746 |
# File 'lib/svn-command/svn_command.rb', line 743 def import(*args) p args svn :exec, 'import', *(args) end |
#latest_revision(*args) ⇒ Object
849 850 851 |
# File 'lib/svn-command/svn_command.rb', line 849 def latest_revision(*args) puts Subversion.latest_revision end |
#log(*args) ⇒ Object
579 580 581 582 |
# File 'lib/svn-command/svn_command.rb', line 579 def log(*args) puts Subversion.log( prepare_args(args) ) #svn :exec, *args end |
#mkdir(*directories) ⇒ Object
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 |
# File 'lib/svn-command/svn_command.rb', line 601 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
649 650 651 652 653 654 655 656 657 658 659 660 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 |
# File 'lib/svn-command/svn_command.rb', line 649 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
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/svn-command/svn_command.rb', line 250 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
842 843 844 |
# File 'lib/svn-command/svn_command.rb', line 842 def repository_root(*args) puts Subversion.repository_root(*args) end |
#repository_uuid(*args) ⇒ Object
Returns the UUID for a working copy/URL
836 837 838 |
# File 'lib/svn-command/svn_command.rb', line 836 def repository_uuid(*args) puts Subversion.repository_uuid(*args) end |
#revisions(directory = './') ⇒ Object
1286 1287 1288 1289 1290 1291 1292 1293 1294 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 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 |
# File 'lib/svn-command/svn_command.rb', line 1286 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!), 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 revisions = Subversion.revisions(directory) puts "#{revisions.length.to_s.bold} revisions found. Starting with #{@reverse ? 'oldest' : 'most recent'} revision and #{@reverse ? 'going forward in time' : 'going backward in time'}..." revisions.instance_variable_get(:@revisions).reverse! if @reverse revision_ids = revisions.map(&:identifier) target_rev = nil # revision_ids.first show_revision_again = 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 # Display the revision if show_revision_again puts((' '*100).green.underline) 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 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") else show_revision_again = true end # Display the menu 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/Enter'.white.bold + ' keys > ' ) # Get response from user and then act on it begin # rescue response = "" response = $stdin.getch.downcase # 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 'v' # View this changeset revs_to_compare = [other_rev, rev] puts "\n"*10 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 show_revision_again = false 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_again = 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_again = false when 'l' # List revision properties puts puts Subversion::printable_revision_properties(rev) show_revision_again = 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_again = false when 'c' # Cat all files from revision puts Subversion.print_commands! do puts Subversion.cat(directory, '-r', rev) end show_revision_again = 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_again = false when 'm' # Edit log message puts Subversion.print_commands! do SvnCommand.execute("edit_message -r #{rev}") end show_revision_again = 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 # Skip / Do nothing with this file puts " Next..." next else # Invalid option. Do nothing. #puts response.inspect puts show_revision_again = 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
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 |
# File 'lib/svn-command/svn_command.rb', line 1169 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
762 763 764 |
# File 'lib/svn-command/svn_command.rb', line 762 def status(*args) print Subversion.status_lines_filter( Subversion.status(*(prepare_args(args))) ) end |
#under_version_control(*args) ⇒ Object
824 825 826 |
# File 'lib/svn-command/svn_command.rb', line 824 def under_version_control(*args) puts Subversion.under_version_control?(*args) end |
#update(*args) ⇒ Object
798 799 800 801 802 803 |
# File 'lib/svn-command/svn_command.rb', line 798 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
818 819 820 |
# File 'lib/svn-command/svn_command.rb', line 818 def url(*args) puts Subversion.url(*args) end |
#view_commits(path = "./") ⇒ Object
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 |
# File 'lib/svn-command/svn_command.rb', line 875 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/svn-command@2349 --diff-cmd colordiff end |
#working_copy_root(*args) ⇒ Object
Returns root/base path for a working copy
830 831 832 |
# File 'lib/svn-command/svn_command.rb', line 830 def working_copy_root(*args) puts Subversion.working_copy_root(*args) end |