svn-command 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/subversion.rb +20 -3
- data/lib/svn_command.rb +91 -40
- data/test/shared/test_helper.rb +3 -1
- data/test/svn_command_test.rb +15 -6
- data/test/test_helper.rb +2 -2
- metadata +2 -3
- data/test/shared/test_helpers/assertions.rb +0 -57
data/lib/subversion.rb
CHANGED
@@ -329,6 +329,7 @@ module Subversion
|
|
329
329
|
# Each ExternalsContainer contains a set of "entries", which are the actual directories listed in the <tt>svn:externals</tt>
|
330
330
|
# property and are "pulled into" the directory.
|
331
331
|
class ExternalsContainer
|
332
|
+
ExternalItem = Struct.new(:name, :repository_path)
|
332
333
|
attr_reader :container_dir
|
333
334
|
attr_reader :entries
|
334
335
|
|
@@ -342,10 +343,26 @@ module Subversion
|
|
342
343
|
@entries.size > 0
|
343
344
|
end
|
344
345
|
|
346
|
+
def entries_structs
|
347
|
+
entries.chomp.enum(:each_line).map { |line|
|
348
|
+
line =~ /^(\S+)\s*(\S+)/
|
349
|
+
ExternalItem.new($1, $2)
|
350
|
+
}
|
351
|
+
end
|
352
|
+
|
345
353
|
def to_s
|
346
|
-
|
347
|
-
|
348
|
-
|
354
|
+
entries_structs = entries_structs()
|
355
|
+
longest_item_name =
|
356
|
+
[
|
357
|
+
entries_structs.map { |entry|
|
358
|
+
entry.name.size
|
359
|
+
}.max,
|
360
|
+
25
|
361
|
+
].max
|
362
|
+
|
363
|
+
container_dir.bold + "\n" +
|
364
|
+
entries_structs.map { |entry|
|
365
|
+
" * " + entry.name.ljust(longest_item_name + 1) + entry.repository_path + "\n"
|
349
366
|
}.join
|
350
367
|
end
|
351
368
|
|
data/lib/svn_command.rb
CHANGED
@@ -5,6 +5,7 @@ require_gem 'facets', '>=1.8.51'
|
|
5
5
|
require 'facets/core/string/margin'
|
6
6
|
require 'facets/core/kernel/require_local'
|
7
7
|
require 'facets/core/array/select' # select!
|
8
|
+
require 'facets/core/kernel/with' # returning
|
8
9
|
|
9
10
|
require_gem 'qualitysmith_extensions', '>=0.0.3'
|
10
11
|
require 'qualitysmith_extensions/enumerable/enum'
|
@@ -19,7 +20,7 @@ require 'pp'
|
|
19
20
|
require 'termios'
|
20
21
|
require 'stringio'
|
21
22
|
require_gem 'colored'
|
22
|
-
require 'colored' # Lets us do "
|
23
|
+
require 'colored' # Lets us do "a".white.bold instead of "\033[1ma\033[0m"
|
23
24
|
require_local '../lib/subversion'
|
24
25
|
require_local '../lib/subversion_extensions'
|
25
26
|
|
@@ -47,6 +48,9 @@ class String
|
|
47
48
|
self << "Exited with error!".bold.red if !$?.success?
|
48
49
|
self
|
49
50
|
end
|
51
|
+
def relativize_path
|
52
|
+
self.gsub(File.expand_path(FileUtils.getwd) + '/', '') # Simplify the directory by removing the working directory from it, if possible
|
53
|
+
end
|
50
54
|
end
|
51
55
|
|
52
56
|
Subversion.extend(Subversion::Extensions)
|
@@ -67,7 +71,7 @@ module Subversion
|
|
67
71
|
# This shouldn't be necessary. Console::Command should allow introspection. But until such time...
|
68
72
|
@@subcommand_list = [
|
69
73
|
'each_unadded',
|
70
|
-
'
|
74
|
+
'externals_items', 'externals_outline', 'externals_containers', 'edit_externals', 'externalize',
|
71
75
|
'ignore',
|
72
76
|
'get_message', 'set_message', 'edit_message',
|
73
77
|
'view_commits'
|
@@ -247,9 +251,9 @@ module Subversion
|
|
247
251
|
# :todo: Finish...
|
248
252
|
|
249
253
|
when nil
|
250
|
-
puts "You are using
|
251
|
-
puts "svn-command is installed at:
|
252
|
-
puts "Use the full path to bypass this wrapper:
|
254
|
+
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 + ", a colorful, useful replacement/wrapper for the standard svn command."
|
255
|
+
puts "svn-command is installed at: " + $0.bold
|
256
|
+
puts "Use the full path to bypass this wrapper: " + Subversion.executable.bold
|
253
257
|
puts
|
254
258
|
puts Subversion.help(subcommand).gsub(<<End, '')
|
255
259
|
|
@@ -532,21 +536,60 @@ End
|
|
532
536
|
# vendor/a
|
533
537
|
# vendor/b
|
534
538
|
# Where 'vendor' is an ExternalsContainer containing external items 'a' and 'b'.
|
539
|
+
# (Use the -o/--omit-repository-path option if you just want the external paths/names without the repository paths)
|
540
|
+
module ExternalsItems
|
541
|
+
def __omit_repository_path
|
542
|
+
@omit_repository_path = true
|
543
|
+
end
|
544
|
+
alias_method :__omit_repository, :__omit_repository_path
|
545
|
+
alias_method :_o, :__omit_repository_path
|
546
|
+
alias_method :_name_only, :__omit_repository_path
|
547
|
+
end
|
535
548
|
def externals_items(directory = "./")
|
536
|
-
|
537
|
-
|
549
|
+
longest_path_name = 25
|
550
|
+
|
551
|
+
externals_structs = Subversion.externals_containers(directory).map do |external|
|
552
|
+
returning(
|
553
|
+
external.entries_structs.map do |entry|
|
554
|
+
Struct.new(:path, :repository_path).new(
|
555
|
+
File.join(external.container_dir, entry.name).relativize_path,
|
556
|
+
entry.repository_path
|
557
|
+
)
|
558
|
+
end
|
559
|
+
) do |entries_structs|
|
560
|
+
longest_path_name =
|
561
|
+
[
|
562
|
+
longest_path_name,
|
563
|
+
entries_structs.map { |entry|
|
564
|
+
entry.path.size
|
565
|
+
}.max
|
566
|
+
].max
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
puts '(Use the -o/--omit-repository-path option if you just want the external paths/names without the repository paths)' unless @omit_repository_path
|
571
|
+
puts externals_structs.map { |entries_structs|
|
572
|
+
entries_structs.map { |entry|
|
573
|
+
entry.path.ljust(longest_path_name + 1) +
|
574
|
+
(@omit_repository_path ? '' : entry.repository_path)
|
575
|
+
}
|
538
576
|
}
|
539
577
|
end
|
578
|
+
alias_subcommand :ei => :externals_items
|
579
|
+
alias_subcommand :externals_list => :externals_items
|
580
|
+
alias_subcommand :el => :externals_items
|
581
|
+
alias_subcommand :externals => :externals_items
|
582
|
+
alias_subcommand :e => :externals_items
|
583
|
+
|
540
584
|
|
541
|
-
# For every directory that has the svn:externals property set, this lists the contents of
|
542
|
-
def
|
585
|
+
# 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
|
586
|
+
def externals_outline(directory = "./")
|
543
587
|
puts Subversion.externals_containers(directory).map { |external|
|
544
|
-
external.to_s.
|
545
|
-
gsub(File.expand_path(Dir.pwd) + '/', '')
|
588
|
+
external.to_s.relativize_path
|
546
589
|
}
|
547
590
|
end
|
548
|
-
alias_subcommand :
|
549
|
-
alias_subcommand :
|
591
|
+
alias_subcommand :e_outline => :externals_outline
|
592
|
+
alias_subcommand :eo => :externals_outline
|
550
593
|
|
551
594
|
# Lists *directories* that have the svn:externals property set.
|
552
595
|
def externals_containers(directory = "./")
|
@@ -554,34 +597,38 @@ End
|
|
554
597
|
external.container_dir
|
555
598
|
}
|
556
599
|
end
|
600
|
+
alias_subcommand :e_containers => :externals_containers
|
557
601
|
|
558
602
|
def edit_externals(directory = nil)
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
603
|
+
catch :exit do
|
604
|
+
if directory.nil? || !Subversion::ExternalsContainer.new(directory).has_entries?
|
605
|
+
if directory.nil?
|
606
|
+
puts "No directory specified. Editing externals for *all* externals dirs..."
|
607
|
+
directory = "./"
|
608
|
+
else
|
609
|
+
puts "Editing externals for *all* externals dirs..."
|
610
|
+
end
|
611
|
+
Subversion.externals_containers(directory).each do |external|
|
612
|
+
puts external.to_s
|
613
|
+
command = "#{Subversion.executable} propedit svn:externals #{external.container_dir}"
|
614
|
+
#puts command
|
615
|
+
begin
|
616
|
+
#print "Press Ctrl-C to skip, any other key to continue. (This will start up your default editor.) "
|
617
|
+
print "Do you want to edit svn:externals for this directory?".black_on_white + ' ' + 'yes'.menu_item(:white) + '/' + 'No'.menu_item(:white) + " > "
|
618
|
+
response = $stdin.getc.chr
|
619
|
+
system command if response.downcase == 'y'
|
620
|
+
rescue Interrupt
|
621
|
+
puts "Goodbye"
|
622
|
+
throw :exit
|
623
|
+
ensure
|
624
|
+
puts
|
625
|
+
end
|
579
626
|
end
|
627
|
+
puts 'Done'
|
628
|
+
else
|
629
|
+
system "#{Subversion.executable} propedit svn:externals #{directory}"
|
580
630
|
end
|
581
|
-
|
582
|
-
else
|
583
|
-
system "#{Subversion.executable} propedit svn:externals #{directory}"
|
584
|
-
end
|
631
|
+
end # catch :exit
|
585
632
|
end
|
586
633
|
alias_subcommand :edit_ext => :edit_externals
|
587
634
|
alias_subcommand :ee => :edit_externals
|
@@ -598,10 +645,14 @@ End
|
|
598
645
|
def __as(as); @as = as; end
|
599
646
|
def as; @as; end
|
600
647
|
end
|
601
|
-
|
602
|
-
|
648
|
+
# svn externalize http://your/repo/shared_tasks/tasks --as shared
|
649
|
+
# or
|
650
|
+
# svn externalize http://your/repo/shared_tasks/tasks shared
|
651
|
+
def externalize(repo_path, as_arg = nil)
|
652
|
+
# :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
|
653
|
+
# :todo: automated test for as_arg/as combo
|
603
654
|
|
604
|
-
Subversion.externalize(repo_path, {:as => as })
|
655
|
+
Subversion.externalize(repo_path, {:as => as || as_arg})
|
605
656
|
end
|
606
657
|
|
607
658
|
|
data/test/shared/test_helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
1
|
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
require_gem 'qualitysmith_extensions'
|
4
|
+
require 'qualitysmith_extensions/test/all'
|
2
5
|
require File.expand_path(File.dirname(__FILE__)+'/' + 'test_helpers/test_colorizer')
|
3
|
-
require File.expand_path(File.dirname(__FILE__)+'/' + 'test_helpers/assertions')
|
data/test/svn_command_test.rb
CHANGED
@@ -50,7 +50,7 @@ class ArgEscapingTest < BaseSvnCommandTest
|
|
50
50
|
# Don't worry, this'll never happen, because the shell will expand the * *before* it gets to SvnCommand. But if you *did* sneak in an asterisk to SvnCommand.execute somehow, this is what would happen...
|
51
51
|
SvnCommand.execute("add dir/* --non-recursive")
|
52
52
|
assert_equal "svn add --non-recursive 'dir/*'", Subversion.executed.join
|
53
|
-
# Actually, I lied... The * will *not* be expanded
|
53
|
+
# Actually, I lied... The * will *not* be expanded in the (rather uncommon) case that there are *no files matching the glob*. But that seems like a bash/shell problem, not our concern. Demo:
|
54
54
|
# > mkdir foo
|
55
55
|
# > echo foo/*
|
56
56
|
# foo/*
|
@@ -359,21 +359,30 @@ class SvnExternalsTest < BaseSvnCommandTest
|
|
359
359
|
end
|
360
360
|
|
361
361
|
|
362
|
-
def
|
362
|
+
def test_svn_externals_outline
|
363
363
|
set_up_stubs
|
364
|
-
output = capture_output { SvnCommand.execute('
|
364
|
+
output = capture_output { SvnCommand.execute('externals_outline') }
|
365
365
|
|
366
366
|
assert_contains output, %q(
|
367
367
|
|/home/tyler/code/gemables/svn-command/test
|
368
|
-
| * shared
|
368
|
+
| * shared http://code.qualitysmith.com/gemables/test_extensions/lib
|
369
369
|
|/home/tyler/code/gemables/svn-command/tasks
|
370
|
-
| * shared
|
370
|
+
| * shared http://code.qualitysmith.com/gemables/shared_tasks/tasks
|
371
371
|
|/home/tyler/code/gemables/svn-command/doc_include
|
372
|
-
| * template
|
372
|
+
| * template http://code.qualitysmith.com/gemables/template/doc/template
|
373
373
|
).margin
|
374
374
|
assert_equal [], Subversion.executed
|
375
375
|
end
|
376
376
|
|
377
|
+
def test_svn_externals_items
|
378
|
+
set_up_stubs
|
379
|
+
output = capture_output { SvnCommand.execute('externals_items') }
|
380
|
+
|
381
|
+
# :todo:
|
382
|
+
|
383
|
+
assert_equal [], Subversion.executed
|
384
|
+
end
|
385
|
+
|
377
386
|
def test_svn_externals_containers
|
378
387
|
set_up_stubs
|
379
388
|
output = capture_output { SvnCommand.execute('externals_containers') }
|
data/test/test_helper.rb
CHANGED
@@ -9,8 +9,8 @@ require_local "shared/test_helper"
|
|
9
9
|
|
10
10
|
require_gem 'qualitysmith_extensions', '>=0.0.3'
|
11
11
|
require 'qualitysmith_extensions/test/assert_exception.rb'
|
12
|
-
require 'qualitysmith_extensions/capture_output.rb'
|
13
|
-
require 'qualitysmith_extensions/simulate_input.rb'
|
12
|
+
require 'qualitysmith_extensions/kernel/capture_output.rb'
|
13
|
+
require 'qualitysmith_extensions/kernel/simulate_input.rb'
|
14
14
|
|
15
15
|
require 'subversion'
|
16
16
|
if $mock_subversion
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: svn-command
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2007-03-
|
6
|
+
version: 0.0.8
|
7
|
+
date: 2007-03-22 00:00:00 -07:00
|
8
8
|
summary: A nifty wrapper command for Subversion's command-line svn client
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -37,7 +37,6 @@ files:
|
|
37
37
|
- test/subversion_test.rb
|
38
38
|
- test/svn_command_test.rb
|
39
39
|
- test/shared/test_helper.rb
|
40
|
-
- test/shared/test_helpers/assertions.rb
|
41
40
|
- test/shared/test_helpers/test_colorizer.rb
|
42
41
|
- bin/rscm_test
|
43
42
|
- bin/change_all_externals.sh
|
@@ -1,57 +0,0 @@
|
|
1
|
-
# Custom assertions
|
2
|
-
class Test::Unit::TestCase
|
3
|
-
def assert_user_error(error_message)
|
4
|
-
assert_tag({
|
5
|
-
:attributes => { :id => "errorExplanation" },
|
6
|
-
:descendant => {
|
7
|
-
:content => error_message
|
8
|
-
}
|
9
|
-
})
|
10
|
-
end
|
11
|
-
|
12
|
-
def assert_includes(container, expected_contents, failure_message = nil)
|
13
|
-
failure_message = build_message(failure_message, "Container <?> was expected to contain <?> but it didn't", container, expected_contents)
|
14
|
-
assert_block(failure_message) do
|
15
|
-
container.include?(expected_contents)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
alias_method :assert_contains, :assert_includes
|
19
|
-
|
20
|
-
# Asserts that the block that is passed in causes the value of the specified variable (+variable+) to change.
|
21
|
-
# +variable+ should be a Proc that, when evaluated, returns the current value of the variable.
|
22
|
-
#
|
23
|
-
# Options:
|
24
|
-
# * If the optional +:from+ option is supplied, it also asserts that it had that initial value.
|
25
|
-
# * If the optional +:to+ option is supplied, it also asserts that it changed _to_ that value.
|
26
|
-
#
|
27
|
-
# So instead of doing this:
|
28
|
-
# assert_equal 1, Model.count
|
29
|
-
# do_something_that_should_cause_count_to_increase
|
30
|
-
# assert_equal 2, Model.count
|
31
|
-
# we can do this:
|
32
|
-
# assert_changed(lambda {ErrorType.count}, :from => 1, :to => 2) do
|
33
|
-
# do_something_that_should_cause_count_to_increase
|
34
|
-
# end
|
35
|
-
# Or, if we don't care what it's changing _from_ as long as it increases in value _by_ 1, we can write this:
|
36
|
-
# assert_changed(c = lambda {ErrorType.count}, :to => c.call+1) do
|
37
|
-
# do_something_that_should_cause_count_to_increase
|
38
|
-
# end
|
39
|
-
# instead of this:
|
40
|
-
# before = Model.count
|
41
|
-
# do_something_that_should_cause_count_to_increase
|
42
|
-
# assert_equal before + 1, Model.count
|
43
|
-
#
|
44
|
-
def assert_changed(variable, options = {}, &block)
|
45
|
-
expected_from = options.delete(:from) || variable.call
|
46
|
-
|
47
|
-
assert_equal expected_from, variable.call
|
48
|
-
|
49
|
-
failure_message = build_message(failure_message, "The variable was expected to change from <?> to <?> but it didn't", variable.call, options.delete(:to) || "something else")
|
50
|
-
assert_block(failure_message) do
|
51
|
-
before = variable.call
|
52
|
-
yield
|
53
|
-
expected_to = options.delete(:to) || variable.call
|
54
|
-
before != variable.call and variable.call == expected_to
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|