subwrap 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,7 +5,7 @@ module Project
5
5
  PrettyName = "Subwrap: Enhanced Subversion Command"
6
6
  Name = "subwrap"
7
7
  RubyForgeName = "subwrap"
8
- Version = "0.4.0"
8
+ Version = "0.5.0"
9
9
  Specification = Gem::Specification.new do |s|
10
10
  s.name = Project::Name
11
11
  s.summary = "A nifty wrapper command for Subversion's command-line svn client"
@@ -20,8 +20,8 @@ module Project
20
20
  s.platform = Gem::Platform::RUBY
21
21
  s.add_dependency("colored")
22
22
  #s.add_dependency("escape")
23
- s.add_dependency("facets")
24
- s.add_dependency("quality_extensions")
23
+ s.add_dependency("facets", '> 2.4.4')
24
+ s.add_dependency("quality_extensions", '> 1.1.0')
25
25
  s.add_dependency("rscm")
26
26
  s.post_install_message = <<-End
27
27
  ---------------------------------------------------------------------------------------------------
data/Readme CHANGED
@@ -102,7 +102,7 @@ New subcommands:
102
102
 
103
103
  == <tt>svn each_unadded</tt>
104
104
 
105
- My personal favorite. This command is useful for keeping your working copies clean -- getting rid of all those accumulated temp files (or *ignoring* or *adding* them if they're something that _all_ users of this repository should be aware of).
105
+ This command is useful for keeping your working copies clean -- getting rid of all those accumulated temp files (or *ignoring* or *adding* them if they're something that _all_ users of this repository should be aware of).
106
106
 
107
107
  It simply goes through each "unadded" file (each file reporting a status of <tt>?</tt>) reported by <tt>svn status</tt> and asks you what you want to do with them -- *add*, *delete*, or *ignore*.
108
108
 
@@ -126,7 +126,21 @@ It simply goes through each "unadded" file (each file reporting a status of <tt>
126
126
 
127
127
  For *files*, it will show a preview of the _contents_ of that file (limited to the first 55 lines); for *directories*, it will show a _directory_ _listing_. By looking at the preview, you should hopefully be able to decide whether you want to _keep_ the file or _junk_ it.
128
128
 
129
- == <tt>svn revisions</tt> (revisions browser)
129
+ == <tt>svn whats_new</tt> (replacement for <tt>svn update</tt>)
130
+
131
+ Whereas <tt>svn update</tt> <i>only</i> updates (merges) with the latest changes and shows you which files were updated/etc., <tt>svn whats_new</tt>:
132
+ * updates (merges) with the latest changes
133
+ * shows you a summary of which files were updated/added/removed/conflict (:todo:)
134
+ * shows the commit messages for each change_set [since you last ran this command :todo:]
135
+ * shows the actual changes (diffs) that were made for every file in the
136
+
137
+ It's a lot like <tt>svn browse</tt> (and in fact shares most of the same code with it), except it's <i>non-interactive</i>, so you just run it and then sit back and watch all the pretty output -- which is a good thing, because doing a diff for each changeset can take a long time...
138
+
139
+ Tip: When actively working on a project with lots of frequent committers, I like to keep a separate tab open in my terminal where I periodicaly run <tt>svn whats_new</tt>:
140
+ * to grab the latest changes from everyone else on the team, and
141
+ * to skim through their changes to see what's changed.
142
+
143
+ == <tt>svn browse</tt> (revisions browser)
130
144
 
131
145
  Lets you interactively browse through all revisions of a file/directory/repository (one at a time). For each revision, it will ask you what you want to do with it (view the changeset, edit revision properties, etc.).
132
146
 
File without changes
File without changes
File without changes
File without changes
data/bin/svn CHANGED
File without changes
@@ -1,4 +1,6 @@
1
1
  # This is the auto-require, which I suppose never gets used any more thanks to RubyGems' annoying change
2
- $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__)))
2
+
3
+ $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__))) # This is mainly for development, to make sure the development version is used instead of loading the same file from the installed gem because the gem path happens to be earlier on in the $LOAD_PATH.
4
+ $LOAD_PATH.uniq!
3
5
  require 'subwrap/subversion'
4
6
  Subversion
@@ -10,7 +10,7 @@ require 'rubygems'
10
10
  gem 'facets'
11
11
  require 'facets/kernel/silence'
12
12
  silence_warnings do
13
- require 'facets/kernel/load'
13
+ require 'facets/kernel/require_local'
14
14
  require 'facets/kernel/in'
15
15
  require 'facets/enumerable/uniq_by'
16
16
  require 'facets/fileutils/which'
@@ -54,6 +54,11 @@ module Subversion
54
54
  mattr_accessor :print_commands
55
55
  mguard_method :print_commands!, :@@print_commands
56
56
 
57
+ @@cached_commands = {}
58
+ @@cached_commands[:latest_revision] = {}
59
+
60
+ #-------------------------------------------------------------------------------------------------
61
+
57
62
  # Adds the given items to the repository. Items may contain wildcards.
58
63
  def self.add(*args)
59
64
  execute "add #{args.join ' '}"
@@ -322,18 +327,27 @@ module Subversion
322
327
  args = ['./'] if args.empty?
323
328
  execute "log #{args.join(' ')}"
324
329
  end
330
+
325
331
  # Returns the revision number for head.
326
- def self.latest_revision(*args)
327
- args = ['./'] if args.empty?
328
- # The revision returned by svn status -u seems to be a pretty reliable way to get this. Does anyone know of a better way?
329
- matches = /Status against revision:\s+(\d+)/m.match(status_against_server(args))
330
- matches && matches[1]
332
+ def self.latest_revision(path = './')
333
+ (cached = @@cached_commands[:latest_revision][path]) and return cached
334
+ url = url(path)
335
+
336
+ #puts "Fetching latest revision from repository: #{url}"
337
+ result = latest_revision_for_path(url).to_i
338
+ @@cached_commands[:latest_revision][path] = result
339
+ result
331
340
  end
341
+
332
342
  # Returns the revision number for the working directory(/file?) specified by +path+
333
343
  def self.latest_revision_for_path(path)
334
344
  # The revision returned by svn info seems to be a pretty reliable way to get this. Does anyone know of a better way?
335
345
  matches = info(path).match(/^Revision: (\d+)/)
336
- matches && matches[1]
346
+ if matches
347
+ matches[1].to_i
348
+ else
349
+ raise "Could not extract revision from #{info(path)}"
350
+ end
337
351
  end
338
352
 
339
353
  # Returns an array of RSCM::Revision objects
@@ -345,6 +359,7 @@ module Subversion
345
359
  args = (['-v'] + args)
346
360
  log_output = Subversion.log(*args)
347
361
  parser = ::RSCM::SubversionLogParser.new(io = StringIO.new(log_output), url = 'http://ignore.me.com')
362
+ # :todo: svn revisions -r 747 -- chops off line
348
363
  revisions = parser.parse_revisions
349
364
  revisions
350
365
  end
@@ -460,7 +475,9 @@ protected
460
475
  p command
461
476
  end
462
477
  if Subversion.print_commands
478
+ #puts '{print'
463
479
  p command
480
+ #puts '}print'
464
481
  end
465
482
 
466
483
  valid_options = [:capture, :exec, :popen]
@@ -98,7 +98,7 @@ module Subversion
98
98
  if before_externals != ""
99
99
  if options[:files_only]
100
100
  before_externals = before_externals.strip.
101
- gsub(/^ ?#{Status_flags.to_regexp_char_class} */, '') \
101
+ gsub(/^ ?#{Status_flags.to_regexp_char_class}..... /, '') \
102
102
  + "\n"
103
103
  else
104
104
  before_externals = before_externals.strip.colorize_svn_status_lines + "\n"
@@ -1,9 +1,10 @@
1
1
  # Tested by: ../../test/svn_command_test.rb
2
2
 
3
+ require File.dirname(__FILE__) + '/../subwrap'
4
+
3
5
  require 'rubygems'
4
6
 
5
7
  require 'facets'
6
- #gem 'facets', '>=1.8.51'
7
8
  #require 'facets/more/command' # Not until Facets includes my changes
8
9
  #require 'facets/kernel/load'
9
10
  #require 'facets/kernel/with' # returning
@@ -23,6 +24,7 @@ require 'quality_extensions/array/expand_ranges'
23
24
  require 'quality_extensions/array/shell_escape'
24
25
  require 'quality_extensions/file_test/binary_file'
25
26
  require 'quality_extensions/console/command'
27
+ require 'quality_extensions/string/with_knowledge_of_color'
26
28
  require 'quality_extensions/module/attribute_accessors'
27
29
  #require 'quality_extensions/module/class_methods'
28
30
 
@@ -779,15 +781,14 @@ End
779
781
  [:__ignore_externals] => 0,
780
782
  }.merge(SvnCommand::C_standard_remote_command_options), self
781
783
  )
782
- def __modified
783
- @only_statuses << 'M'
784
- end
784
+ def __modified; @only_statuses << 'M'; end
785
+ def __added; @only_statuses << 'A'; end
786
+ def __untracked; @only_statuses << '?'; end
787
+ def __deleted; @only_statuses << 'D'; end
785
788
  alias_method :_M, :__modified
786
-
787
- def __added
788
- @only_statuses << 'A'
789
- end
790
789
  alias_method :_A, :__added
790
+ alias_method :_?, :__untracked
791
+ alias_method :_D, :__deleted
791
792
 
792
793
  #document :__files_only do
793
794
  "Only list filenames, not statuses"
@@ -843,6 +844,10 @@ End
843
844
  end
844
845
 
845
846
  def update(*args)
847
+ directory = (args[0] ||= './')
848
+ revision_of_directory = Subversion.latest_revision_for_path(directory)
849
+ puts "(Note: The working copy '#{directory.white.bold}' was at #{('r' + revision_of_directory.to_s).magenta.bold} before updating...)"
850
+
846
851
  @passthrough_options << '--ignore-externals' if ignore_externals?
847
852
  Subversion.print_commands! do # Print the commands and options used so they can be reminded that they're using user_preferences['update']['ignore_externals']...
848
853
  puts Subversion.update_lines_filter( Subversion.update(*prepare_args(args)) )
@@ -909,6 +914,8 @@ End
909
914
  #
910
915
  # Pass in a list of revisions/revision ranges ("134", "134:136", "134-136", and "134-136 139" are all valid)
911
916
  #
917
+ # :todo: How is this different from whats_new?
918
+ #
912
919
  module ViewCommits
913
920
  def _r(*revisions)
914
921
  # This is necessary so that the -r option doesn't accidentally eat up an arg that wasn't meant to be a revision (a filename, for instance). The only problem with this is if there's actully a filename that matches these patterns! (But then we could just re-order ars.)
@@ -1360,16 +1367,6 @@ End
1360
1367
  raise NotImplementedError
1361
1368
  end
1362
1369
 
1363
- #-----------------------------------------------------------------------------------------------------------------------------
1364
- # This is designed to be a convenient replacement to the svn update command for those who wish to not only see a *list* of
1365
- # which files were updated as the update occurs but also wish to see *what changed* for each of those files.
1366
- # So this command will effectively do a diff on each updated file and show you what has changed (= "what's new").
1367
- module WhatsNew
1368
- end
1369
- def whats_new
1370
- SvnCommand.execute("revisions --whats-new --non-interactive")
1371
- end
1372
-
1373
1370
  #-----------------------------------------------------------------------------------------------------------------------------
1374
1371
  # :todo: Pre-fetch svn diff in the background (fork the process) so you don't have to wait, in interactive mode.
1375
1372
  # :todo: When calling this command on a single file,
@@ -1378,7 +1375,7 @@ End
1378
1375
  # :todo: add number aliases (1) for view changeset, etc. so you can use numpad exclusively
1379
1376
  # :todo: rename interactive mode to different name, s.a. browse_revisions
1380
1377
  # Add --grep option to non-interactively search all changesets returned for a pattern.
1381
- module Revisions
1378
+ module ShowOrBrowseRevisions
1382
1379
  # We will pass all of these options through to 'svn log'
1383
1380
  Console::Command.pass_through({
1384
1381
  [:_q, :__quiet] => 0,
@@ -1387,7 +1384,7 @@ End
1387
1384
  [:__stop_on_copy] => 0,
1388
1385
  [:__incremental] => 0,
1389
1386
  [:__xml] => 0,
1390
- [:__limit] => 1,
1387
+ #[:__limit] => 1,
1391
1388
  }.merge(SvnCommand::C_standard_remote_command_options), self
1392
1389
  )
1393
1390
 
@@ -1405,17 +1402,35 @@ End
1405
1402
  alias_method :_r, :__revision
1406
1403
 
1407
1404
  #-------------------------------------------------------------------------
1408
- # :todo: Problem: I often forget to run this *before* doing an svn update. But as soon as I do an update, base is updated and now there is *nothing* new since last update.
1409
- # Possible solution: Keep a log of updates (at least all updates that use this wrapper) and let you go back to any previous update as your starting point if you've updated very recently and want to go back farther than that.
1410
- # (Or maybe .svn has a record of the previous update time somewhere that we can pick up?)
1411
- # Also, as soon as you do an svn revisions, it detects that it's out of date and forces an update, making it so that you can't repeat the command and get the same results.
1412
- #
1405
+ def __all
1406
+ @first_revision = '1'
1407
+ @last_revision = 'head'
1408
+ @oldest_first_default = false
1409
+ @limit = false
1410
+ end
1411
+
1412
+ def __limit(limit)
1413
+ @limit = limit
1414
+ end
1415
+
1413
1416
  def __since_last_update
1414
- @revisions = '%base%:head'
1415
- @newest_first_default = false
1417
+ @first_revision = '%base%'
1418
+ @last_revision = 'head'
1419
+ @oldest_first_default = true
1416
1420
  end
1417
1421
  alias_method :__from_base, :__since_last_update
1418
1422
  alias_method :__since_base, :__since_last_update
1423
+
1424
+ # :todo: Problem: I often forget to run this *before* doing an svn update. But as soon as I do an update, base is updated and now there is *nothing* new since last update.
1425
+ # Possible solution:
1426
+ # :todo: Keep a log of updates (at least all updates that use this wrapper) and let you go back to any previous update as your starting point if you've updated very recently and want to go back farther than that.
1427
+ # (Or maybe .svn has a record of the previous update time somewhere that we can pick up?)
1428
+ #
1429
+ def __whats_new
1430
+ @first_revision = '%base%'
1431
+ @last_revision = 'head'
1432
+ @oldest_first_default = true
1433
+ end
1419
1434
  alias_method :__new, :__since_last_update
1420
1435
  alias_method :__whats_new, :__since_last_update
1421
1436
 
@@ -1425,14 +1440,23 @@ End
1425
1440
  # Use chronic?
1426
1441
  # :todo:
1427
1442
  def __from(revision)
1428
- @revisions = "#{revision}:head"
1429
- @newest_first_default = false
1443
+ @first_revision = revision
1444
+ @last_revision = 'head'
1445
+ @oldest_first_default = true
1430
1446
  end
1431
1447
  alias_method :__since, :__from
1432
1448
 
1433
1449
  def __back_to(revision)
1434
- @revisions = "#{revision}:head"
1435
- @newest_first_default = true
1450
+ @first_revision = revision
1451
+ @last_revision = 'head'
1452
+ @oldest_first_default = false
1453
+ end
1454
+
1455
+ # :todo: if they're not at the root of the repo, this may not give them what they want
1456
+ # they may want the last revisions for a specific file, in which case the latest_revision will likely not be the right revision number
1457
+ def __last(revision_count)
1458
+ @first_revision = Subversion.latest_revision - revision_count.to_i + 1
1459
+ @last_revision = Subversion.latest_revision
1436
1460
  end
1437
1461
 
1438
1462
  #-------------------------------------------------------------------------
@@ -1455,14 +1479,14 @@ End
1455
1479
  #-------------------------------------------------------------------------
1456
1480
  # Start at earlier revision and go forwards rather than starting at the latest revision
1457
1481
  def __oldest_first
1458
- @newest_first = false
1482
+ @oldest_first = true
1459
1483
  end
1460
1484
  alias_method :__forward, :__oldest_first
1461
1485
  alias_method :__forwards, :__oldest_first
1462
1486
  alias_method :__chronological, :__oldest_first
1463
1487
 
1464
1488
  def __newest_first
1465
- @newest_first = true
1489
+ @oldest_first = false
1466
1490
  end
1467
1491
  alias_method :__reverse, :__newest_first
1468
1492
  alias_method :__backwards, :__newest_first
@@ -1476,6 +1500,10 @@ End
1476
1500
  end
1477
1501
  alias_method :__ni, :__non_interactive
1478
1502
 
1503
+ def __paged
1504
+ @paged = true
1505
+ end
1506
+
1479
1507
  def __interactive
1480
1508
  @interactive = true
1481
1509
  end
@@ -1497,70 +1525,169 @@ End
1497
1525
  end
1498
1526
  end
1499
1527
  # :todo: what if they pass in *2* filenames?
1500
- def revisions(directory = './')
1501
- puts "Getting list of revisions for '#{directory.white.bold}' ..."
1528
+ # See also: the implementation of revisions() in /usr/lib/ruby/gems/1.8/gems/rscm-0.5.1/lib/rscm/scm/subversion.rb
1529
+
1530
+ module Revisions
1531
+ def self.extended(base)
1532
+ base.extend ShowOrBrowseRevisions
1533
+ end
1534
+ end
1535
+ def play_revisions(directory = './')
1536
+ @interactive = false
1537
+ show_or_browse_revisions(directory)
1538
+ end
1539
+ alias_subcommand :changesets => :revisions
1540
+ alias_subcommand :show_log => :revisions
1541
+ alias_subcommand :show_revisions => :revisions
1542
+ alias_subcommand :show_changesets => :revisions
1543
+
1544
+ module Browse
1545
+ def self.extended(base)
1546
+ base.extend ShowOrBrowseRevisions
1547
+ end
1548
+ end
1549
+ def browse(directory = './')
1550
+ @interactive = true
1551
+ show_or_browse_revisions(directory)
1552
+ end
1553
+ alias_subcommand :revisions => :browse
1554
+ alias_subcommand :browse => :browse
1555
+ alias_subcommand :browse_log => :browse
1556
+ alias_subcommand :browse_revisions => :browse
1557
+ alias_subcommand :browse_changesets => :browse
1558
+ # Other so-far-rejected name ideas: list_commits, changeset_browser, log_browser, interactive_log
1559
+
1560
+ # This is designed to be a convenient replacement to the svn update command for those who wish to not only see a *list* of
1561
+ # which files were updated as the update occurs but also wish to see *what changed* for each of those files.
1562
+ # So this command will effectively do a diff on each updated file and show you what has changed (= "what's new").
1563
+ #
1564
+ # Should this command run an update or do people want to run this command after an update??
1565
+ # Nah... an update can be really slow... and they may have just done one...
1566
+ module WhatsNew
1567
+ def self.extended(base)
1568
+ base.extend ShowOrBrowseRevisions
1569
+ end
1570
+ end
1571
+ def whats_new(directory = './')
1572
+ revision_of_directory = Subversion.latest_revision_for_path(directory)
1573
+
1574
+ #__whats_new
1575
+ # (allow this to be overriden with, for example, a --since option)
1576
+ @first_revision_default = revision_of_directory.to_s
1577
+ @last_revision_default = 'head'
1578
+ @oldest_first_default = true
1579
+
1580
+ #puts "Updating..."
1581
+ #Subversion.update(directory) # silent
1582
+ #Subversion.execute("update")
1502
1583
 
1584
+ @interactive = false
1585
+ show_or_browse_revisions(directory)
1586
+ end
1587
+
1588
+ #-------------------------------------------------------------------------
1589
+ protected
1590
+ def show_or_browse_revisions(directory = './')
1503
1591
  #-----------------------------
1504
1592
  head = Subversion.latest_revision
1505
1593
  revision_of_directory = Subversion.latest_revision_for_path(directory)
1506
1594
 
1507
- # 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
1508
- # only list revisions up to that revision (actually looks like it only goes up to and including Last Changed Rev: 2838,
1509
- # not Revision: 2839, as reported by svn info...)
1595
+ # By default, if you just do an svn log (which is what we do to get the metadata about each revision), svn will only show revisions up to and Last Changed Rev.
1596
+ # So if there have been newer revisions since then, it won't show the log messages for them.
1597
+ # I can't think of a good reason why it shouldn't. I think it's a bug in the svn client.
1598
+ #
1599
+ # Also, it's possible for the Last Changed Rev of to be "out of date" even if you were the last committer!
1600
+ # If you commit file lib/foo.rb, the Last Changed Rev of lib/foo.rb may be 13 but the Last Changed Rev of . will still be 10 until you update '.'.
1601
+ # In other words each *directory* has a different Last Changed Rev.
1602
+ #
1603
+ # Anyway, to work around this bug, we explicitly get the head revision number from the server and pass that as the ending revision number to svn log.
1604
+ # So in our example, we would pass -r 1:13 to svn log even when doing `svn browse .`, to ensure that we get information for all revisions
1605
+ # all the way up to head (13).
1606
+ #
1607
+ # :todo: do the same for svn log
1510
1608
  if revision_of_directory and head and revision_of_directory < head
1511
- puts "The working copy '#{directory.white.bold}' appears to be out-of-date (#{revision_of_directory}) with respect to the head revision (#{head}). Updating..."
1512
- Subversion.update(directory)
1609
+ puts "The working copy '#{directory.white.bold}' appears to be out-of-date (#{revision_of_directory.to_s.magenta.bold}) with respect to the head revision (#{head.to_s.magenta.bold}). Just so ya know..."
1610
+ #Subversion.update(directory)
1513
1611
  end
1514
1612
  #-----------------------------
1515
1613
 
1516
1614
  args = [directory]
1517
- #@revisions ||= '1:head' # this was messing with --limit 5, making it start at 1 instead of most recent
1518
- if @revisions
1519
- @revisions.gsub! /%base%/, revision_of_directory
1520
- args.concat ['-r', @revisions]
1615
+
1616
+ unless @revisions
1617
+ @first_revision_default ||= '1' #'%base%'
1618
+ @last_revision_default ||= 'head'
1619
+
1620
+ @first_revision ||= @first_revision_default
1621
+ @last_revision ||= @last_revision_default
1622
+ #@first_revision, @last_revision = @last_revision, @first_revision if @oldest_first
1623
+ @revisions = "#{@first_revision}:#{@last_revision}"
1521
1624
  end
1625
+ @revisions.gsub! /%base%/, revision_of_directory.to_s
1626
+ args.concat ['-r', @revisions]
1522
1627
 
1523
- @newest_first_default.nil? ? @newest_first_default = false : nil
1524
- @newest_first.nil? ? @newest_first = @newest_first_default : nil
1628
+ @limit_default = nil #10
1629
+ @limit = @limit_default if @limit.nil? and @limit_default
1630
+ args.concat ['--limit', @limit_default.to_s] if @limit
1631
+
1632
+ @oldest_first_default = true if @oldest_first_default.nil?
1633
+ @oldest_first = @oldest_first_default if @oldest_first.nil?
1525
1634
 
1526
1635
  @show_diffs ||= true if !@interactive
1527
1636
  @show_diffs_default ||= false
1528
1637
  @show_diffs ||= @show_diffs_default
1529
1638
 
1530
1639
  if @show_file_list.nil?
1531
- if directory != './' # They specified a (non-default) directory/file
1532
- @show_file_list = false
1533
- else
1640
+ if directory == './' # They are using the default directory
1534
1641
  @show_file_list = true
1642
+ else
1643
+ @show_file_list = false
1535
1644
  end
1536
1645
  end
1537
1646
 
1538
- run_pager if !@interactive
1647
+ #puts "@interactive=#{@interactive}"
1648
+ #puts "@oldest_first=#{@oldest_first}"
1649
+ #puts "@revisions=#{@revisions}"
1650
+ #pp prepare_args(args)
1539
1651
 
1540
1652
  #-----------------------------
1541
- #pp prepare_args(args)
1542
- revisions = Subversion.revisions(*prepare_args(args))
1653
+ puts "Getting revision details for '#{directory.green.bold}', revisions #{@revisions.magenta.bold} #{"(up to #{@limit} of them) " if @limit}(this may take a moment) ..."
1654
+ #require 'unroller'
1655
+ #Unroller.trace :dir_match => __FILE__ do
1656
+ #Subversion.print_commands! do
1657
+ revisions = Subversion.revisions(*prepare_args(args))
1658
+ #end
1659
+ #end
1543
1660
 
1544
- #puts "@newest_first=#{@newest_first}"
1545
- 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' }..."
1546
- revisions.instance_variable_get(:@revisions).reverse! if @newest_first
1661
+ #-----------------------------
1662
+ run_pager if !@interactive and @paged
1663
+ puts "#{revisions.length.to_s.bold} revisions found. Starting with #{(@oldest_first ? 'oldest' : 'most recent').white.bold} revision and #{@oldest_first ? 'going forward in time' : 'going backward in time' }..."
1664
+ #pp revisions.map {|r| [r.identifier, r.time]}
1665
+ revisions.instance_variable_get(:@revisions).reverse! unless @oldest_first # :todo: or just swap first and last when building @revisions? no, I think there are some cases when that wouldn't work...
1547
1666
  revision_ids = revisions.map(&:identifier)
1548
1667
 
1549
1668
  #-----------------------------------------------------------------------
1550
1669
  # The main loop through the array of revisions
1551
- target_rev = nil # revision_ids.first
1670
+ #revisions.each do |revision|
1671
+ i = 0
1672
+ #target_rev = nil # revision_ids.first
1552
1673
  show_revision = true
1674
+ show_menu = true
1675
+ revision = revisions[i]
1676
+ begin # rescue
1677
+ loop do
1678
+ show_revision = false if show_menu == false
1553
1679
 
1554
- revisions.each do |revision|
1555
1680
  rev = revision.identifier
1556
1681
  other_rev = rev-1
1557
- if target_rev
1558
- if rev == target_rev
1559
- target_rev = nil # We have arrived.
1560
- else
1561
- next # Keep going (hopefully in the right direction!)
1562
- end
1563
- end
1682
+ counter = revision_ids.index(rev) + 1
1683
+
1684
+ #if target_rev
1685
+ # if rev == target_rev
1686
+ # target_rev = nil # We have arrived.
1687
+ # else
1688
+ # next # Keep going (hopefully in the right direction!)
1689
+ # end
1690
+ #end
1564
1691
 
1565
1692
  #-----------------------------------------------------------------------
1566
1693
  show_diffs = proc {
@@ -1568,7 +1695,7 @@ End
1568
1695
  #puts "\n"*10
1569
1696
  puts
1570
1697
  puts((' '*100).green.underline)
1571
- print "Diffing #{revs_to_compare.min}:#{revs_to_compare.max}... ".bold
1698
+ print "Diffing #{revs_to_compare.min.to_s.magenta.bold}:#{revs_to_compare.max.to_s.magenta.bold}... ".bold
1572
1699
  puts
1573
1700
  #Subversion.repository_root
1574
1701
  #Subversion.print_commands! do
@@ -1579,14 +1706,15 @@ End
1579
1706
  #-----------------------------------------------------------------------
1580
1707
  # Display the revision (number, date, description, files changed)
1581
1708
  if show_revision
1582
-
1583
1709
  #puts((' '*100).green.underline)
1584
1710
  puts
1585
- puts((' '*100).on_green)
1711
+ #puts((' '*100).on_green)
1586
1712
 
1587
- puts "#{revisions.length - revision_ids.index(rev)}. ".green.bold +
1588
- "r#{rev}".magenta.bold + (rev == head ? ' (head)'.bold : '') +
1589
- " | #{revision.developer} | #{revision.time.strftime('%Y-%m-%d %H:%M:%S')}".magenta.bold
1713
+ #puts "#{revisions.length - revision_ids.index(rev)}. ".green.bold +
1714
+ puts (
1715
+ "r#{rev}".white.bold.on_green + (rev == head ? ' (head)'.bold.on_green : '') +
1716
+ " | #{revision.developer} | #{revision.time.strftime('%Y-%m-%d %H:%M:%S')}".white.bold.on_green
1717
+ ).ljust_with_color(100, ' '.on_green)
1590
1718
  puts revision.message
1591
1719
  puts
1592
1720
  #pp revision
@@ -1605,32 +1733,28 @@ End
1605
1733
  show_diffs.call
1606
1734
  end
1607
1735
 
1608
- #-----------------------------------------------------------------------
1609
- # Display the menu
1610
- if @interactive
1611
- print(
1612
- "r#{rev}".magenta.on_blue.bold + ': ' +
1613
- 'View this changeset'.menu_item(:cyan) + ', ' +
1614
- 'Diff against specific revision'.menu_item(:cyan, 'D') + ', ' +
1615
- 'Grep the changeset'.menu_item(:cyan, 'G') + ', ' +
1616
- 'List or '.menu_item(:magenta, 'L') + '' +
1617
- 'Edit revision properties'.menu_item(:magenta, 'E') + ', ' +
1618
- 'svn Cat all files'.menu_item(:cyan, 'C') + ', ' +
1619
- 'grep the cat'.menu_item(:cyan, 'a') + ', ' + "\n " +
1620
- 'mark as Reviewed'.menu_item(:green, 'R') + ', ' +
1621
- 'edit log Message'.menu_item(:yellow, 'M') + ', ' +
1622
- 'or ' + 'browse using ' + 'Up/Down/Space/Enter'.white.bold + ' keys > '
1623
- )
1624
- end
1625
1736
 
1626
1737
  #-----------------------------------------------------------------------
1627
1738
  # Get response from user and then act on it
1628
- begin # rescue
1739
+ go = nil
1740
+ catch :prev_or_next do
1741
+ loop do
1742
+ go = :nowhere
1743
+
1744
+ #-----------------------------------------------------------------------
1745
+ # Display the menu
1746
+ if @interactive and show_menu
1747
+ print "r#{rev}".magenta.on_blue.bold + " (#{counter}/#{revisions.length})" + " (#{'?'.bold} for help)" + ' > '
1748
+ end
1749
+
1750
+ #-----------------------------------------------------------------------
1629
1751
  if @interactive
1630
1752
  response = ""
1631
1753
  response = $stdin.getch.downcase
1632
1754
  else
1633
- response = "\n"
1755
+ #response = "\n"
1756
+ go = :next
1757
+ throw :prev_or_next
1634
1758
  end
1635
1759
 
1636
1760
  # Escape sequence such as the up arrow key ("\e[A")
@@ -1649,6 +1773,25 @@ End
1649
1773
  end
1650
1774
 
1651
1775
  case response
1776
+
1777
+ when '?' # Help
1778
+ show_menu = false
1779
+ puts
1780
+ puts(
1781
+ 'View this changeset'.menu_item(:cyan) + ', ' +
1782
+ 'Diff against specific revision'.menu_item(:cyan, 'D') + ', ' +
1783
+ 'Grep the changeset'.menu_item(:cyan, 'G') + ', ' +
1784
+ 'List or '.menu_item(:magenta, 'L') + '' +
1785
+ 'Edit revision properties'.menu_item(:magenta, 'E') + ', ' +
1786
+ 'svn Cat all files'.menu_item(:cyan, 'C') + ', ' +
1787
+ 'grep the cat'.menu_item(:cyan, 'a') + ', ' + "\n " +
1788
+ 'mark as Reviewed'.menu_item(:green, 'R') + ', ' +
1789
+ 'edit log Message'.menu_item(:yellow, 'M') + ', ' +
1790
+ 'browse using ' + 'Up/Down/Left/Right/Space/Enter'.white.bold + ' keys' + ', ' +
1791
+ 'Quit'.menu_item(:magenta)
1792
+ )
1793
+ show_revision = false # only show the menu
1794
+
1652
1795
  when '1', 'v' # View this changeset
1653
1796
  show_diffs.call
1654
1797
  show_revision = false # only show the menu
@@ -1755,42 +1898,69 @@ End
1755
1898
  end
1756
1899
  show_revision = false
1757
1900
 
1758
- when "\e[A" # Up
1759
- i = revision_ids.index(rev)
1760
- target_rev = revision_ids[i - 1]
1901
+ when "\e[A", "\e\[D" # Previous (Up or Left)
1902
+ #i = revision_ids.index(rev)
1903
+ #target_rev = revision_ids[i - 1]
1761
1904
  puts " Previous..."
1762
- retry
1905
+ go = :prev
1906
+ throw :prev_or_next
1907
+ #retry
1763
1908
 
1764
-
1765
- when /\n|\e\[B| / # Enter or Down or Space
1909
+ when "\n", "\e\[B", "\e\[C", " " # Next (Enter or Down or Right or Space)
1766
1910
  # Skip / Do nothing with this file
1767
1911
  puts " Next..."
1768
- #show_revision = false #?
1769
- next
1912
+ go = :next
1913
+ throw :prev_or_next
1914
+ #next
1915
+
1916
+ when 'q' # Quit
1917
+ raise Interrupt, "Quitting"
1770
1918
 
1771
1919
  else
1772
1920
  # Invalid option. Do nothing.
1773
1921
  #puts response.inspect
1774
1922
  puts
1923
+ show_menu = false
1775
1924
  show_revision = false
1776
1925
 
1777
1926
  end # case response
1778
1927
 
1779
- redo # Until they tell us they're ready to move on...
1928
+ end # loop until they tell us they're ready to move on...
1929
+ end # catch :prev_or_next
1780
1930
 
1781
- rescue Interrupt
1782
- puts "\nGoodbye!"
1783
- return
1784
- end # rescue
1785
- end
1931
+ case go
1932
+ when :prev
1933
+ if i-1 < 0
1934
+ show_menu = false
1935
+ puts "Can't go back -- already at first revision in set!".red
1936
+ else
1937
+ show_menu = show_revision = true
1938
+ i -= 1
1939
+ end
1940
+ when :next
1941
+ if i+1 > revisions.length-1
1942
+ # We've reached the end
1943
+ if @interactive
1944
+ show_menu = false
1945
+ puts "Can't go forward -- already at last revision in set!".red
1946
+ else
1947
+ break
1948
+ end
1949
+ else
1950
+ show_menu = show_revision = true
1951
+ i += 1
1952
+ end
1953
+ end
1954
+ revision = revisions[i]
1955
+
1956
+ end # loop / revisions.each
1957
+
1958
+ rescue Interrupt
1959
+ puts "\nGoodbye!"
1960
+ return
1961
+ end # rescue
1786
1962
  end
1787
- alias_subcommand :changesets => :revisions
1788
- alias_subcommand :browse => :revisions
1789
- alias_subcommand :browse_log => :revisions
1790
- alias_subcommand :browse_revisions => :revisions
1791
- alias_subcommand :browse_changesets => :revisions
1792
- # See also the implementation of revisions() in /usr/lib/ruby/gems/1.8/gems/rscm-0.5.1/lib/rscm/scm/subversion.rb
1793
- # Other name ideas: browse, list_commits, changeset_browser, log_browser, interactive_log
1963
+ public
1794
1964
 
1795
1965
  #-----------------------------------------------------------------------------------------------------------------------------
1796
1966
  # Aliases
metadata CHANGED
@@ -1,115 +1,126 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
4
2
  name: subwrap
5
3
  version: !ruby/object:Gem::Version
6
- version: 0.4.0
7
- date: 2008-06-19 00:00:00 -07:00
8
- summary: A nifty wrapper command for Subversion's command-line svn client
9
- require_paths:
10
- - lib
11
- email: rubyforge.org@tylerrick.com
12
- homepage: http://subwrap.rubyforge.org/
13
- rubyforge_project: subwrap
14
- description: This is a wrapper command for Subversion's command-line svn client that adds a few new subcommands.
15
- autorequire:
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
4
+ version: 0.5.0
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message: |
29
- ---------------------------------------------------------------------------------------------------
30
- You should now be able to run the subwrap command.
31
-
32
- IMPORTANT: If you want to replace the normal svn command with subwrap, please run
33
- sudo `which _subwrap_post_install` or check the Readme to find out how to manually add it to your path.
34
-
35
- Also, it is recommended that you install the termios gem so that you don't have to press enter
36
- after selecting an option from the menu, but it will work without it.
37
- ---------------------------------------------------------------------------------------------------
38
-
39
6
  authors:
40
7
  - Tyler Rick
41
- files:
42
- - lib/subwrap/subversion_extensions.rb
43
- - lib/subwrap/subversion.rb
44
- - lib/subwrap/svn_command.rb
45
- - lib/subwrap/pager.rb
46
- - lib/subwrap.rb
47
- - test/subversion_extensions_test.rb
48
- - test/svn_command_test.rb
49
- - test/subversion_test.rb
50
- - test/test_helper.rb
51
- - bin/subwrap
52
- - bin/rscm_test
53
- - bin/command_completion_for_subwrap
54
- - bin/svn
55
- - bin/_subwrap_post_install
56
- - ProjectInfo.rb
57
- - Readme
58
- test_files:
59
- - test/subversion_extensions_test.rb
60
- - test/svn_command_test.rb
61
- - test/subversion_test.rb
62
- - test/test_helper.rb
63
- rdoc_options:
64
- - --title
65
- - subwrap
66
- - --main
67
- - Readme
68
- - --line-numbers
69
- extra_rdoc_files:
70
- - Readme
71
- executables:
72
- - command_completion_for_subwrap
73
- - _subwrap_post_install
74
- - subwrap
75
- extensions: []
76
-
77
- requirements: []
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
78
11
 
12
+ date: 2008-09-17 00:00:00 -07:00
13
+ default_executable:
79
14
  dependencies:
80
15
  - !ruby/object:Gem::Dependency
81
16
  name: colored
17
+ type: :runtime
82
18
  version_requirement:
83
- version_requirements: !ruby/object:Gem::Version::Requirement
19
+ version_requirements: !ruby/object:Gem::Requirement
84
20
  requirements:
85
- - - ">"
21
+ - - ">="
86
22
  - !ruby/object:Gem::Version
87
- version: 0.0.0
23
+ version: "0"
88
24
  version:
89
25
  - !ruby/object:Gem::Dependency
90
26
  name: facets
27
+ type: :runtime
91
28
  version_requirement:
92
- version_requirements: !ruby/object:Gem::Version::Requirement
29
+ version_requirements: !ruby/object:Gem::Requirement
93
30
  requirements:
94
31
  - - ">"
95
32
  - !ruby/object:Gem::Version
96
- version: 0.0.0
33
+ version: 2.4.4
97
34
  version:
98
35
  - !ruby/object:Gem::Dependency
99
36
  name: quality_extensions
37
+ type: :runtime
100
38
  version_requirement:
101
- version_requirements: !ruby/object:Gem::Version::Requirement
39
+ version_requirements: !ruby/object:Gem::Requirement
102
40
  requirements:
103
41
  - - ">"
104
42
  - !ruby/object:Gem::Version
105
- version: 0.0.0
43
+ version: 1.1.0
106
44
  version:
107
45
  - !ruby/object:Gem::Dependency
108
46
  name: rscm
47
+ type: :runtime
109
48
  version_requirement:
110
- version_requirements: !ruby/object:Gem::Version::Requirement
49
+ version_requirements: !ruby/object:Gem::Requirement
111
50
  requirements:
112
- - - ">"
51
+ - - ">="
113
52
  - !ruby/object:Gem::Version
114
- version: 0.0.0
53
+ version: "0"
115
54
  version:
55
+ description: This is a wrapper command for Subversion's command-line svn client that adds a few new subcommands.
56
+ email: rubyforge.org@tylerrick.com
57
+ executables:
58
+ - command_completion_for_subwrap
59
+ - _subwrap_post_install
60
+ - subwrap
61
+ extensions: []
62
+
63
+ extra_rdoc_files:
64
+ - Readme
65
+ files:
66
+ - lib/subwrap/subversion_extensions.rb
67
+ - lib/subwrap/subversion.rb
68
+ - lib/subwrap/svn_command.rb
69
+ - lib/subwrap/pager.rb
70
+ - lib/subwrap.rb
71
+ - test/subversion_extensions_test.rb
72
+ - test/svn_command_test.rb
73
+ - test/subversion_test.rb
74
+ - test/test_helper.rb
75
+ - bin/subwrap
76
+ - bin/rscm_test
77
+ - bin/command_completion_for_subwrap
78
+ - bin/svn
79
+ - bin/_subwrap_post_install
80
+ - ProjectInfo.rb
81
+ - Readme
82
+ has_rdoc: true
83
+ homepage: http://subwrap.rubyforge.org/
84
+ post_install_message: |
85
+ ---------------------------------------------------------------------------------------------------
86
+ You should now be able to run the subwrap command.
87
+
88
+ IMPORTANT: If you want to replace the normal svn command with subwrap, please run
89
+ sudo `which _subwrap_post_install` or check the Readme to find out how to manually add it to your path.
90
+
91
+ Also, it is recommended that you install the termios gem so that you don't have to press enter
92
+ after selecting an option from the menu, but it will work without it.
93
+ ---------------------------------------------------------------------------------------------------
94
+
95
+ rdoc_options:
96
+ - --title
97
+ - subwrap
98
+ - --main
99
+ - Readme
100
+ - --line-numbers
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: "0"
108
+ version:
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: "0"
114
+ version:
115
+ requirements: []
116
+
117
+ rubyforge_project: subwrap
118
+ rubygems_version: 1.2.0
119
+ signing_key:
120
+ specification_version: 2
121
+ summary: A nifty wrapper command for Subversion's command-line svn client
122
+ test_files:
123
+ - test/subversion_extensions_test.rb
124
+ - test/svn_command_test.rb
125
+ - test/subversion_test.rb
126
+ - test/test_helper.rb