rubycut-babushka 0.10.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +31 -0
  3. data/README.markdown +246 -0
  4. data/Rakefile +26 -0
  5. data/bin/babushka +11 -0
  6. data/deps/babushka.rb +101 -0
  7. data/deps/dev.rb +12 -0
  8. data/deps/fhs.rb +31 -0
  9. data/deps/git.rb +29 -0
  10. data/deps/homebrew.rb +30 -0
  11. data/deps/os_x.rb +33 -0
  12. data/deps/packages.rb +22 -0
  13. data/deps/pkg_managers.rb +110 -0
  14. data/deps/ruby.rb +23 -0
  15. data/deps/rubygems.rb +24 -0
  16. data/deps/system.rb +10 -0
  17. data/deps/templates/app.rb +68 -0
  18. data/deps/templates/external.rb +12 -0
  19. data/deps/templates/installer.rb +31 -0
  20. data/deps/templates/managed.rb +105 -0
  21. data/deps/templates/ppa.rb +24 -0
  22. data/deps/templates/src.rb +42 -0
  23. data/deps/templates/tmbundle.rb +15 -0
  24. data/lib/babushka.rb +28 -0
  25. data/lib/babushka/accepts_block_for.rb +72 -0
  26. data/lib/babushka/accepts_list_for.rb +49 -0
  27. data/lib/babushka/accepts_value_for.rb +24 -0
  28. data/lib/babushka/base.rb +78 -0
  29. data/lib/babushka/bug_reporter.rb +55 -0
  30. data/lib/babushka/cmdline.rb +133 -0
  31. data/lib/babushka/cmdline/handler.rb +41 -0
  32. data/lib/babushka/cmdline/helpers.rb +127 -0
  33. data/lib/babushka/cmdline/parser.rb +69 -0
  34. data/lib/babushka/colorizer.rb +59 -0
  35. data/lib/babushka/core_patches/array.rb +171 -0
  36. data/lib/babushka/core_patches/blank.rb +22 -0
  37. data/lib/babushka/core_patches/bytes.rb +52 -0
  38. data/lib/babushka/core_patches/hash.rb +107 -0
  39. data/lib/babushka/core_patches/hashish.rb +14 -0
  40. data/lib/babushka/core_patches/integer.rb +25 -0
  41. data/lib/babushka/core_patches/io.rb +8 -0
  42. data/lib/babushka/core_patches/numeric.rb +16 -0
  43. data/lib/babushka/core_patches/object.rb +27 -0
  44. data/lib/babushka/core_patches/string.rb +116 -0
  45. data/lib/babushka/core_patches/symbol.rb +12 -0
  46. data/lib/babushka/core_patches/try.rb +15 -0
  47. data/lib/babushka/core_patches/uri.rb +24 -0
  48. data/lib/babushka/dep.rb +470 -0
  49. data/lib/babushka/dep_context.rb +18 -0
  50. data/lib/babushka/dep_definer.rb +115 -0
  51. data/lib/babushka/dep_pool.rb +49 -0
  52. data/lib/babushka/dep_runner.rb +85 -0
  53. data/lib/babushka/dsl.rb +26 -0
  54. data/lib/babushka/git_repo.rb +185 -0
  55. data/lib/babushka/helpers/git_helpers.rb +32 -0
  56. data/lib/babushka/helpers/log_helpers.rb +176 -0
  57. data/lib/babushka/helpers/path_helpers.rb +34 -0
  58. data/lib/babushka/helpers/run_helpers.rb +145 -0
  59. data/lib/babushka/helpers/shell_helpers.rb +229 -0
  60. data/lib/babushka/helpers/suggest_helpers.rb +16 -0
  61. data/lib/babushka/helpers/uri_helpers.rb +36 -0
  62. data/lib/babushka/ip.rb +160 -0
  63. data/lib/babushka/lambda_chooser.rb +40 -0
  64. data/lib/babushka/levenshtein.rb +125 -0
  65. data/lib/babushka/meta_dep.rb +65 -0
  66. data/lib/babushka/meta_dep_context.rb +15 -0
  67. data/lib/babushka/parameter.rb +143 -0
  68. data/lib/babushka/pkg_helper.rb +81 -0
  69. data/lib/babushka/pkg_helpers/apt_helper.rb +61 -0
  70. data/lib/babushka/pkg_helpers/base_helper.rb +19 -0
  71. data/lib/babushka/pkg_helpers/binpkgsrc_helper.rb +48 -0
  72. data/lib/babushka/pkg_helpers/binports_helper.rb +34 -0
  73. data/lib/babushka/pkg_helpers/brew_helper.rb +110 -0
  74. data/lib/babushka/pkg_helpers/gem_helper.rb +120 -0
  75. data/lib/babushka/pkg_helpers/macports_helper.rb +22 -0
  76. data/lib/babushka/pkg_helpers/npm_helper.rb +45 -0
  77. data/lib/babushka/pkg_helpers/pacman_helper.rb +27 -0
  78. data/lib/babushka/pkg_helpers/pip_helper.rb +45 -0
  79. data/lib/babushka/pkg_helpers/src_helper.rb +16 -0
  80. data/lib/babushka/pkg_helpers/yum_helper.rb +25 -0
  81. data/lib/babushka/popen.rb +40 -0
  82. data/lib/babushka/prompt.rb +176 -0
  83. data/lib/babushka/renderable.rb +67 -0
  84. data/lib/babushka/resource.rb +215 -0
  85. data/lib/babushka/run_reporter.rb +60 -0
  86. data/lib/babushka/shell.rb +108 -0
  87. data/lib/babushka/source.rb +216 -0
  88. data/lib/babushka/source_pool.rb +146 -0
  89. data/lib/babushka/system_definitions.rb +97 -0
  90. data/lib/babushka/system_profile.rb +210 -0
  91. data/lib/babushka/task.rb +142 -0
  92. data/lib/babushka/vars.rb +108 -0
  93. data/lib/babushka/version_of.rb +65 -0
  94. data/lib/babushka/version_str.rb +57 -0
  95. data/lib/babushka/xml_string.rb +28 -0
  96. data/lib/components.rb +82 -0
  97. data/lib/fancypath/fancypath.rb +200 -0
  98. data/lib/inkan/inkan.rb +76 -0
  99. data/spec/acceptance/acceptance.rb +43 -0
  100. data/spec/acceptance_helper.rb +113 -0
  101. data/spec/archives/Blah.app.zip +0 -0
  102. data/spec/archives/archive.tar +0 -0
  103. data/spec/archives/archive.tar.bz2 +0 -0
  104. data/spec/archives/archive.tar.gz +0 -0
  105. data/spec/archives/archive.tbz2 +0 -0
  106. data/spec/archives/archive.tgz +0 -0
  107. data/spec/archives/archive.zip +0 -0
  108. data/spec/archives/content.txt +5 -0
  109. data/spec/archives/invalid_archive +5 -0
  110. data/spec/archives/nested archive/content.txt +5 -0
  111. data/spec/archives/nested_archive.tar +0 -0
  112. data/spec/archives/really_a_gzip.zip +0 -0
  113. data/spec/archives/test-0.3.1.tgz +0 -0
  114. data/spec/archives/tgz_archive +0 -0
  115. data/spec/archives/zip_without_extension +0 -0
  116. data/spec/babushka/accepts_for_spec.rb +174 -0
  117. data/spec/babushka/accepts_for_support.rb +72 -0
  118. data/spec/babushka/cmdline/console_spec.rb +11 -0
  119. data/spec/babushka/cmdline/help_spec.rb +61 -0
  120. data/spec/babushka/cmdline/version_spec.rb +10 -0
  121. data/spec/babushka/core_patches_spec.rb +171 -0
  122. data/spec/babushka/dep_context_spec.rb +58 -0
  123. data/spec/babushka/dep_definer_spec.rb +152 -0
  124. data/spec/babushka/dep_definer_support.rb +36 -0
  125. data/spec/babushka/dep_spec.rb +567 -0
  126. data/spec/babushka/dep_support.rb +29 -0
  127. data/spec/babushka/deps_spec.rb +113 -0
  128. data/spec/babushka/gem_helper_spec.rb +90 -0
  129. data/spec/babushka/git_repo_spec.rb +396 -0
  130. data/spec/babushka/ip_spec.rb +131 -0
  131. data/spec/babushka/lambda_chooser_spec.rb +115 -0
  132. data/spec/babushka/meta_dep_definer_spec.rb +127 -0
  133. data/spec/babushka/meta_dep_wrapper_spec.rb +32 -0
  134. data/spec/babushka/parameter_spec.rb +135 -0
  135. data/spec/babushka/path_helpers_spec.rb +102 -0
  136. data/spec/babushka/prompt_spec.rb +188 -0
  137. data/spec/babushka/renderable_spec.rb +100 -0
  138. data/spec/babushka/resource_spec.rb +141 -0
  139. data/spec/babushka/run_helpers_spec.rb +26 -0
  140. data/spec/babushka/shell_helpers_spec.rb +244 -0
  141. data/spec/babushka/shell_spec.rb +19 -0
  142. data/spec/babushka/source_pool_spec.rb +320 -0
  143. data/spec/babushka/source_pool_support.rb +31 -0
  144. data/spec/babushka/source_spec.rb +382 -0
  145. data/spec/babushka/source_support.rb +17 -0
  146. data/spec/babushka/system_profile_spec.rb +61 -0
  147. data/spec/babushka/task_spec.rb +141 -0
  148. data/spec/babushka/uri_spec.rb +13 -0
  149. data/spec/babushka/vars_spec.rb +59 -0
  150. data/spec/babushka/version_of_spec.rb +110 -0
  151. data/spec/babushka/version_str_spec.rb +130 -0
  152. data/spec/babushka/version_str_support.rb +37 -0
  153. data/spec/babushka/xml_string_spec.rb +98 -0
  154. data/spec/deps/bad/broken.rb +7 -0
  155. data/spec/deps/bad/working.rb +3 -0
  156. data/spec/deps/good/meta.rb +14 -0
  157. data/spec/deps/good/test.rb +11 -0
  158. data/spec/deps/outer/deps.rb +19 -0
  159. data/spec/deps/outer/more deps.rb +11 -0
  160. data/spec/deps/params/params.rb +10 -0
  161. data/spec/fancypath/fancypath_spec.rb +272 -0
  162. data/spec/fancypath_support.rb +10 -0
  163. data/spec/inkan/inkan_spec.rb +217 -0
  164. data/spec/renderable/different_example.conf.erb +4 -0
  165. data/spec/renderable/example.conf.erb +3 -0
  166. data/spec/renderable/example.sh +6 -0
  167. data/spec/renderable/with_binding.conf.erb +4 -0
  168. data/spec/renderable/xml_example.conf.erb +8 -0
  169. data/spec/repos/remote.git.tgz +0 -0
  170. data/spec/spec_helper.rb +87 -0
  171. metadata +238 -0
@@ -0,0 +1,29 @@
1
+ def setup_yield_counts
2
+ @yield_counts = Hash.new {|hsh,k| hsh[k] = Hash.new {|hsh,k| 0 } }
3
+
4
+ @yield_counts_none = {}
5
+ @yield_counts_met_run = {:setup => 1, :met? => 1}
6
+ @yield_counts_meet_run = {:setup => 1, :met? => 2, :prepare => 1, :before => 1, :meet => 1, :after => 1}
7
+ @yield_counts_dep_failed = {:setup => 1}
8
+ @yield_counts_failed_meet_run = {:setup => 1, :met? => 2, :prepare => 1, :before => 1, :meet => 1, :after => 1}
9
+ @yield_counts_early_exit_meet_run = {:setup => 1, :met? => 1, :prepare => 1, :before => 1, :meet => 1}
10
+ @yield_counts_already_met = {:setup => 1, :met? => 1}
11
+ @yield_counts_failed_at_before = {:setup => 1, :met? => 2, :prepare => 1, :before => 1}
12
+ end
13
+
14
+ def make_counter_dep opts = {}
15
+ incrementers = DepContext.accepted_blocks.inject({}) {|lambdas,key|
16
+ lambdas[key] = L{ @yield_counts[opts[:name]][key] += 1 }
17
+ lambdas
18
+ }
19
+ dep opts[:name] do
20
+ requires opts[:requires]
21
+ requires_when_unmet opts[:requires_when_unmet]
22
+ DepContext.accepted_blocks.each {|dep_method|
23
+ send dep_method do
24
+ incrementers[dep_method].call
25
+ (opts[dep_method] || default_block_for(dep_method)).call
26
+ end
27
+ }
28
+ end
29
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+ require 'dep_support'
3
+
4
+ shared_examples_for "met?" do
5
+ describe "met?" do
6
+ before { Dep('a').met? }
7
+ it "should met?-check each dep exactly once" do
8
+ %w[a b c d e f].each {|i| @yield_counts[i].should == @yield_counts_already_met }
9
+ end
10
+ it "shouldn't run the meet-only dep" do
11
+ @yield_counts['g'].should == @yield_counts_none
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "an already met dep tree" do
17
+ before {
18
+ setup_yield_counts
19
+ make_counter_dep :name => 'a', :requires => %w[b c]
20
+ make_counter_dep :name => 'b', :requires => %w[c d e]
21
+ make_counter_dep :name => 'c', :requires => %w[f]
22
+ make_counter_dep :name => 'd', :requires => %w[e f], :requires_when_unmet => %w[g]
23
+ make_counter_dep :name => 'e', :requires => %w[f]
24
+ make_counter_dep :name => 'f'
25
+ make_counter_dep :name => 'g'
26
+ }
27
+ it_should_behave_like "met?"
28
+ describe "meet" do
29
+ before { Dep('a').meet }
30
+ it "should meet no deps" do
31
+ %w[a b c d e f].each {|i| @yield_counts[i].should == @yield_counts_already_met }
32
+ end
33
+ it "shouldn't run the meet-only dep" do
34
+ @yield_counts['g'].should == @yield_counts_none
35
+ end
36
+ end
37
+ after { Base.sources.anonymous.deps.clear! }
38
+ end
39
+
40
+ describe "an unmeetable dep tree" do
41
+ before {
42
+ setup_yield_counts
43
+ make_counter_dep :name => 'a', :met? => L{ false }, :requires => %w[b c]
44
+ make_counter_dep :name => 'b', :met? => L{ false }, :requires => %w[c d e]
45
+ make_counter_dep :name => 'c', :met? => L{ false }, :requires => %w[f], :requires_when_unmet => %w[g]
46
+ make_counter_dep :name => 'd', :met? => L{ false }, :requires => %w[e f]
47
+ make_counter_dep :name => 'e', :met? => L{ false }, :requires => %w[f]
48
+ make_counter_dep :name => 'f', :met? => L{ false }
49
+ make_counter_dep :name => 'g', :met? => L{ false }
50
+ }
51
+ it_should_behave_like "met?"
52
+ describe "meet" do
53
+ before { Dep('a').meet }
54
+ it "should fail on the bootom-most dep" do
55
+ %w[f].each {|i| @yield_counts[i].should == @yield_counts_failed_meet_run }
56
+ end
57
+ it "should bubble the fail back up" do
58
+ %w[a b c].each {|i| @yield_counts[i].should == @yield_counts_dep_failed }
59
+ end
60
+ it "shouldn't run any deps after the fail" do
61
+ %w[d e g].each {|i| @yield_counts[i].should == @yield_counts_none }
62
+ end
63
+ end
64
+ after { Base.sources.anonymous.deps.clear! }
65
+ end
66
+
67
+ describe "a meetable dep tree" do
68
+ before {
69
+ setup_yield_counts
70
+ make_counter_dep :name => 'a', :requires => %w[b c] , :met? => L{ @yield_counts['a'][:met?] > 1 }
71
+ make_counter_dep :name => 'b', :requires => %w[c d e], :met? => L{ @yield_counts['b'][:met?] > 1 }
72
+ make_counter_dep :name => 'c', :requires => %w[f] , :met? => L{ @yield_counts['c'][:met?] > 1 }, :requires_when_unmet => %w[g]
73
+ make_counter_dep :name => 'd', :requires => %w[e f] , :met? => L{ @yield_counts['d'][:met?] > 1 }
74
+ make_counter_dep :name => 'e', :requires => %w[f] , :met? => L{ @yield_counts['e'][:met?] > 1 }
75
+ make_counter_dep :name => 'f', :met? => L{ @yield_counts['f'][:met?] > 1 }
76
+ make_counter_dep :name => 'g', :met? => L{ @yield_counts['g'][:met?] > 1 }
77
+ }
78
+ it_should_behave_like "met?"
79
+ describe "meet" do
80
+ before { Dep('a').meet }
81
+ it "should meet each dep exactly once" do
82
+ Base.sources.anonymous.deps.names.each {|i| @yield_counts[i].should == @yield_counts_meet_run }
83
+ end
84
+ end
85
+ after { Base.sources.anonymous.deps.clear! }
86
+ end
87
+
88
+ describe "a partially meetable dep tree" do
89
+ before {
90
+ setup_yield_counts
91
+ make_counter_dep :name => 'a', :requires => %w[b c] , :met? => L{ @yield_counts['a'][:met?] > 1 }
92
+ make_counter_dep :name => 'b', :requires => %w[c d e], :met? => L{ @yield_counts['b'][:met?] > 1 }
93
+ make_counter_dep :name => 'c', :requires => %w[f] , :met? => L{ @yield_counts['c'][:met?] > 1 }, :requires_when_unmet => %w[g]
94
+ make_counter_dep :name => 'd', :requires => %w[e f] , :met? => L{ @yield_counts['d'][:met?] > 1 }
95
+ make_counter_dep :name => 'e', :requires => %w[f] , :met? => L{ false }
96
+ make_counter_dep :name => 'f', :met? => L{ @yield_counts['f'][:met?] > 1 }
97
+ make_counter_dep :name => 'g', :met? => L{ @yield_counts['g'][:met?] > 1 }
98
+ }
99
+ it_should_behave_like "met?"
100
+ describe "meet" do
101
+ before { Dep('a').meet }
102
+ it "should meet deps until one fails" do
103
+ %w[c f g].each {|i| @yield_counts[i].should == @yield_counts_meet_run }
104
+ end
105
+ it "should fail on the unmeetable dep" do
106
+ %w[e].each {|i| @yield_counts[i].should == @yield_counts_failed_meet_run }
107
+ end
108
+ it "should bubble the fail up" do
109
+ %w[a b d].each {|i| @yield_counts[i].should == @yield_counts_dep_failed }
110
+ end
111
+ end
112
+ after { Base.sources.anonymous.deps.clear! }
113
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ def stub_env_info
4
+ GemHelper.stub!(:env_info).and_return(%q{
5
+ RubyGems Environment:
6
+ - INSTALLATION DIRECTORY: /Library/Ruby/Gems/1.8
7
+ })
8
+ end
9
+
10
+ def stub_versions_of
11
+ GemHelper.stub!(:versions_of).and_return([
12
+ VersionStr.new('0.2.11'),
13
+ VersionStr.new('0.2.11.3'),
14
+ VersionStr.new('0.3.7'),
15
+ VersionStr.new('0.3.9')
16
+ ])
17
+ end
18
+
19
+ describe "has?" do
20
+ before {
21
+ stub_versions_of
22
+ }
23
+ it "should report installed gems correctly" do
24
+ GemHelper.has?('hammock 0.3.9').should == VersionStr.new('0.3.9')
25
+ end
26
+ it "should report missing gems correctly" do
27
+ GemHelper.has?('hammock 0.3.8').should be_nil
28
+ end
29
+ it "should report matching gems correctly" do
30
+ GemHelper.has?('hammock >= 0.3.10').should be_nil
31
+ GemHelper.has?('hammock >= 0.3.9').should == VersionStr.new('0.3.9')
32
+ GemHelper.has?('hammock >= 0.3.8').should == VersionStr.new('0.3.9')
33
+ GemHelper.has?('hammock >= 0.3.7').should == VersionStr.new('0.3.9')
34
+ GemHelper.has?('hammock ~> 0.2.7').should == VersionStr.new('0.2.11.3')
35
+ GemHelper.has?('hammock ~> 0.3.7').should == VersionStr.new('0.3.9')
36
+ end
37
+ end
38
+
39
+ describe "gem_path_for" do
40
+ before {
41
+ stub_env_info
42
+ stub_versions_of
43
+ @prefix = '/Library/Ruby/Gems/1.8/gems'
44
+ }
45
+ it "should return the correct path" do
46
+ GemHelper.gem_path_for('hammock').should == @prefix / 'hammock-0.3.9'
47
+ GemHelper.gem_path_for('hammock', '0.3.9').should == @prefix / 'hammock-0.3.9'
48
+ GemHelper.gem_path_for('hammock', '~> 0.3.7').should == @prefix / 'hammock-0.3.9'
49
+ GemHelper.gem_path_for('hammock', '0.3.8').should be_nil
50
+ end
51
+ end
52
+
53
+ describe Babushka::GemHelper do
54
+ describe '.should_sudo?' do
55
+ before :each do
56
+ Babushka::GemHelper.stub!(
57
+ :gem_root => '/path/to/gems'.p,
58
+ :bin_path => '/path/to/bins'.p
59
+ )
60
+ end
61
+
62
+ it "should return true if the bin dir is not writeable" do
63
+ File.should_receive(:writable?).with('/path/to/bins').and_return(false)
64
+ Babushka::GemHelper.should_sudo?.should be_true
65
+ end
66
+
67
+ context "when the bin dir is writable" do
68
+ before {
69
+ File.should_receive(:writable?).with('/path/to/bins').and_return(true)
70
+ }
71
+ it "should return false if the gem dir does not exist" do
72
+ Babushka::GemHelper.gem_root.should_receive(:exists?).and_return(false)
73
+ Babushka::GemHelper.should_sudo?.should be_false
74
+ end
75
+ context "when the gem dir exists" do
76
+ before {
77
+ Babushka::GemHelper.gem_root.should_receive(:exists?).and_return(true)
78
+ }
79
+ it "should return true if the gem dir is not writeable" do
80
+ Babushka::GemHelper.gem_root.should_receive(:writable?).and_return(false)
81
+ Babushka::GemHelper.should_sudo?.should be_true
82
+ end
83
+ it "should return false if the gem dir is writeable" do
84
+ Babushka::GemHelper.gem_root.should_receive(:writable?).and_return(true)
85
+ Babushka::GemHelper.should_sudo?.should be_false
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,396 @@
1
+ require 'spec_helper'
2
+
3
+ def stub_commitless_repo name
4
+ (tmp_prefix / 'repos' / name).rm
5
+ cd tmp_prefix / 'repos' / name, :create => true do
6
+ shell "git init"
7
+ end
8
+ end
9
+
10
+ def stub_repo name
11
+ (tmp_prefix / 'repos' / "#{name}_remote").rm
12
+ cd tmp_prefix / 'repos' / "#{name}_remote", :create => true do
13
+ shell "tar -zxvf #{File.dirname(__FILE__) / '../repos/remote.git.tgz'}"
14
+ end
15
+
16
+ (tmp_prefix / 'repos' / name).rm
17
+ cd tmp_prefix / 'repos' do
18
+ shell "git clone #{name}_remote/remote.git #{name}"
19
+ end
20
+ end
21
+
22
+ def repo_context name, &block
23
+ cd(tmp_prefix / 'repos'/ name, &block)
24
+ end
25
+
26
+ describe GitRepo, 'creation' do
27
+ before(:all) { stub_repo 'a' }
28
+ it "should return nil on nonexistent paths" do
29
+ Babushka::GitRepo.new(tmp_prefix / 'repos/nonexistent').root.should == nil
30
+ end
31
+ it "should return nil on non-repo paths" do
32
+ Babushka::GitRepo.new(tmp_prefix / 'repos').root.should == nil
33
+ end
34
+ it "should recognise the repo path as a string" do
35
+ Babushka::GitRepo.new((tmp_prefix / 'repos/a').to_s).root.should == tmp_prefix / 'repos/a'
36
+ end
37
+ it "should recognise the repo path as a Fancypath" do
38
+ Babushka::GitRepo.new(tmp_prefix / 'repos/a').root.should == tmp_prefix / 'repos/a'
39
+ end
40
+ it "should find the parent when called on the subdir" do
41
+ Babushka::GitRepo.new(tmp_prefix / 'repos/a/lib').root.should == tmp_prefix / 'repos/a'
42
+ end
43
+ it "should find the git dir within the repo" do
44
+ Babushka::GitRepo.new(tmp_prefix / 'repos/a').git_dir.should == tmp_prefix / 'repos/a/.git'
45
+ Babushka::GitRepo.new(tmp_prefix / 'repos/a/lib').git_dir.should == tmp_prefix / 'repos/a/.git'
46
+ end
47
+ it "should store path as a Fancypath" do
48
+ Babushka::GitRepo.new((tmp_prefix / 'repos/a').to_s).path.should be_an_instance_of(Fancypath)
49
+ Babushka::GitRepo.new(tmp_prefix / 'repos/a').path.should be_an_instance_of(Fancypath)
50
+ end
51
+ it "should return the repo path as a Fancypath" do
52
+ Babushka::GitRepo.new((tmp_prefix / 'repos/a').to_s).root.should be_an_instance_of(Fancypath)
53
+ Babushka::GitRepo.new(tmp_prefix / 'repos/a').root.should be_an_instance_of(Fancypath)
54
+ end
55
+ end
56
+
57
+ describe GitRepo, 'without a repo' do
58
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/nonexistent') }
59
+ it "should not exist" do
60
+ subject.exists?.should be_false
61
+ end
62
+ [:clean?, :dirty?, :current_branch, :current_head, :remote_branch_exists?, :ahead?].each {|method|
63
+ it "should raise on #{method}" do
64
+ L{ subject.send(method) }.should raise_error(Babushka::GitRepoError, "There is no repo at #{tmp_prefix / 'repos/nonexistent'}.")
65
+ end
66
+ }
67
+ context "with lazy eval" do
68
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/lazy') }
69
+ it "should fail before the repo is created, but work afterwards" do
70
+ subject.exists?.should be_false
71
+ L{ subject.clean? }.should raise_error(Babushka::GitRepoError, "There is no repo at #{tmp_prefix / 'repos/lazy'}.")
72
+ stub_repo 'lazy'
73
+ subject.exists?.should be_true
74
+ subject.should be_clean
75
+ end
76
+ end
77
+ end
78
+
79
+ describe GitRepo, "with a repo" do
80
+ before(:all) { stub_repo 'a' }
81
+ it "should exist with string path" do
82
+ Babushka::GitRepo.new((tmp_prefix / 'repos/a').to_s).exists?.should be_true
83
+ end
84
+ it "should exist with Fancypath path" do
85
+ Babushka::GitRepo.new(tmp_prefix / 'repos/a').exists?.should be_true
86
+ end
87
+ end
88
+
89
+ describe GitRepo, '#clean? / #dirty?' do
90
+ context "on commitless repos" do
91
+ before(:all) { stub_commitless_repo 'a' }
92
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
93
+ it "should be clean" do
94
+ subject.should be_clean
95
+ subject.should_not be_dirty
96
+ end
97
+ end
98
+ context "on normal repos" do
99
+ before(:all) { stub_repo 'a' }
100
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
101
+ it "should be clean" do
102
+ subject.should be_clean
103
+ subject.should_not be_dirty
104
+ end
105
+ context "when there are changes" do
106
+ before {
107
+ cd(tmp_prefix / 'repos/a') { shell "echo dirt >> content.txt" }
108
+ }
109
+ it "should be dirty" do
110
+ subject.should_not be_clean
111
+ subject.should be_dirty
112
+ end
113
+ context "when the changes are staged" do
114
+ before {
115
+ cd(tmp_prefix / 'repos/a') { shell "git add --update ." }
116
+ }
117
+ it "should be dirty" do
118
+ subject.should_not be_clean
119
+ subject.should be_dirty
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ describe GitRepo, '#include?' do
127
+ before(:all) { stub_repo 'a' }
128
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
129
+ it "should return true for valid commits" do
130
+ subject.include?('20758f2d9d696c51ac83a0fd36626d421057b24d').should be_true
131
+ subject.include?('20758f2').should be_true
132
+ end
133
+ it "should return false for nonexistent commits" do
134
+ subject.include?('20758f2d9d696c51ac83a0fd36626d421057b24e').should be_false
135
+ subject.include?('20758f3').should be_false
136
+ end
137
+ end
138
+
139
+ describe GitRepo, '#branches' do
140
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
141
+ context "on a repo with commits" do
142
+ before(:all) { stub_repo 'a' }
143
+ it "should return the only branch in a list" do
144
+ subject.branches.should == ['master']
145
+ end
146
+ context "after creating another branch" do
147
+ before {
148
+ repo_context('a') { shell "git checkout -b next" }
149
+ }
150
+ it "should return both branches" do
151
+ subject.branches.should == ['master', 'next']
152
+ end
153
+ context "after changing back to master" do
154
+ before {
155
+ repo_context('a') { shell "git checkout master" }
156
+ }
157
+ it "should return both branches" do
158
+ subject.branches.should == ['master', 'next']
159
+ end
160
+ end
161
+ end
162
+ end
163
+ context "on a repo with no commits" do
164
+ before { stub_commitless_repo 'a' }
165
+ it "should return no branches" do
166
+ subject.branches.should == []
167
+ end
168
+ end
169
+ end
170
+
171
+ describe GitRepo, '#current_branch' do
172
+ before(:all) { stub_repo 'a' }
173
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
174
+ it "should return 'master'" do
175
+ subject.current_branch.should == 'master'
176
+ end
177
+ context "after creating another branch" do
178
+ before {
179
+ repo_context('a') { shell "git checkout -b next" }
180
+ }
181
+ it "should return 'next'" do
182
+ subject.current_branch.should == 'next'
183
+ end
184
+ context "after changing back to master" do
185
+ before {
186
+ repo_context('a') { shell "git checkout master" }
187
+ }
188
+ it "should return 'next'" do
189
+ subject.current_branch.should == 'master'
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ describe GitRepo, '#current_head' do
196
+ before { stub_repo 'a' }
197
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
198
+ it "should return a short commit id" do
199
+ subject.current_head.should =~ /^[0-9a-f]{7}$/
200
+ end
201
+ end
202
+
203
+ describe GitRepo, '#current_full_head' do
204
+ before { stub_repo 'a' }
205
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
206
+ it "should return a full commit id" do
207
+ subject.current_full_head.should =~ /^[0-9a-f]{40}$/
208
+ end
209
+ end
210
+
211
+ describe GitRepo, '#ahead?' do
212
+ before(:all) {
213
+ stub_repo 'a'
214
+ cd(tmp_prefix / 'repos/a') {
215
+ shell "git checkout -b topic"
216
+ }
217
+ }
218
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
219
+ it "should have a local topic branch" do
220
+ subject.current_branch.should == 'topic'
221
+ end
222
+ it "should return true if the current branch has no remote" do
223
+ subject.remote_branch_exists?.should be_false
224
+ subject.should be_ahead
225
+ end
226
+ context "when remote branch exists" do
227
+ before(:all) {
228
+ cd(tmp_prefix / 'repos/a') {
229
+ shell "git push origin topic"
230
+ shell 'echo "Ch-ch-ch-changes" >> content.txt'
231
+ shell 'git commit -a -m "Changes!"'
232
+ }
233
+ }
234
+ it "should have a local topic branch" do
235
+ subject.current_branch.should == 'topic'
236
+ end
237
+ it "should return true if there are unpushed commits on the current branch" do
238
+ subject.remote_branch_exists?.should be_true
239
+ subject.should be_ahead
240
+ end
241
+ context "when the branch is fully pushed" do
242
+ before {
243
+ cd(tmp_prefix / 'repos/a') {
244
+ shell "git push origin topic"
245
+ }
246
+ }
247
+ it "should not be ahead" do
248
+ subject.remote_branch_exists?.should be_true
249
+ subject.should_not be_ahead
250
+ end
251
+ end
252
+ end
253
+ end
254
+
255
+ describe GitRepo, '#behind?' do
256
+ before(:all) {
257
+ stub_repo 'a'
258
+ cd(tmp_prefix / 'repos/a') {
259
+ shell "git checkout -b next"
260
+ shell "git reset --hard origin/next^"
261
+ }
262
+ }
263
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
264
+ it "should return true if there are new commits on the remote" do
265
+ subject.remote_branch_exists?.should be_true
266
+ subject.should be_behind
267
+ end
268
+ context "when the remote is merged" do
269
+ before {
270
+ cd(tmp_prefix / 'repos/a') {
271
+ shell "git merge origin/next"
272
+ }
273
+ }
274
+ it "should not be behind" do
275
+ subject.remote_branch_exists?.should be_true
276
+ subject.should_not be_behind
277
+ end
278
+ end
279
+ end
280
+
281
+ describe GitRepo, '#clone!' do
282
+ before(:all) { stub_repo 'a' }
283
+ context "for existing repos" do
284
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
285
+ it "should raise" do
286
+ L{
287
+ subject.clone!('a_remote/remote.git')
288
+ }.should raise_error(GitRepoExists, "Can't clone a_remote/remote.git to existing path #{tmp_prefix / 'repos/a'}.")
289
+ end
290
+ end
291
+ context "for non-existent repos" do
292
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/b') }
293
+ it "should not exist yet" do
294
+ subject.exists?.should be_false
295
+ end
296
+ context "when the clone fails" do
297
+ it "should raise" do
298
+ L{
299
+ subject.clone!(tmp_prefix / 'repos/a_remote/nonexistent.git')
300
+ }.should raise_error(GitRepoError)
301
+ end
302
+ end
303
+ context "after cloning" do
304
+ before { subject.clone! "a_remote/remote.git" }
305
+ it "should exist now" do
306
+ subject.exists?.should be_true
307
+ end
308
+ it "should have the correct remote" do
309
+ subject.repo_shell("git remote -v").should == %Q{
310
+ origin\t#{tmp_prefix / 'repos/a_remote/remote.git'} (fetch)
311
+ origin\t#{tmp_prefix / 'repos/a_remote/remote.git'} (push)
312
+ }.strip
313
+ end
314
+ it "should have the remote branch" do
315
+ subject.repo_shell("git branch -a").should == %Q{
316
+ * master
317
+ remotes/origin/HEAD -> origin/master
318
+ remotes/origin/master
319
+ remotes/origin/next
320
+ }.strip
321
+ end
322
+ end
323
+ after {
324
+ shell "rm -rf #{tmp_prefix / 'repos/b'}"
325
+ }
326
+ end
327
+ end
328
+
329
+ describe GitRepo, '#branch!' do
330
+ before(:all) { stub_repo 'a' }
331
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
332
+ it "should not already have a next branch" do
333
+ subject.branches.should_not include('next')
334
+ end
335
+ context "after tracking" do
336
+ before { subject.branch! "next" }
337
+ it "should have created a next branch" do
338
+ subject.branches.should include('next')
339
+ end
340
+ it "should not be tracking anything" do
341
+ subject.repo_shell('git config branch.next.remote').should be_nil
342
+ end
343
+ end
344
+ end
345
+
346
+ describe GitRepo, '#track!' do
347
+ before(:all) { stub_repo 'a' }
348
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
349
+ it "should not already have a next branch" do
350
+ subject.branches.should_not include('next')
351
+ end
352
+ context "after tracking" do
353
+ before { subject.track! "origin/next" }
354
+ it "should have created a next branch" do
355
+ subject.branches.should include('next')
356
+ end
357
+ it "should be tracking origin/next" do
358
+ subject.repo_shell('git config branch.next.remote').should == 'origin'
359
+ end
360
+ end
361
+ end
362
+
363
+ describe GitRepo, '#checkout!' do
364
+ before(:all) {
365
+ stub_repo 'a'
366
+ cd(tmp_prefix / 'repos/a') {
367
+ shell "git checkout -b next"
368
+ }
369
+ }
370
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
371
+ it "should already have a next branch" do
372
+ subject.branches.should =~ %w[master next]
373
+ subject.current_branch.should == 'next'
374
+ end
375
+ context "after checking out" do
376
+ before { subject.checkout! "master" }
377
+ it "should be on the master branch now" do
378
+ subject.current_branch.should == 'master'
379
+ end
380
+ end
381
+ end
382
+
383
+ describe GitRepo, '#reset_hard!' do
384
+ before {
385
+ stub_repo 'a'
386
+ cd(tmp_prefix / 'repos/a') {
387
+ shell "echo 'more rubies' >> lib/rubies.rb"
388
+ }
389
+ }
390
+ subject { Babushka::GitRepo.new(tmp_prefix / 'repos/a') }
391
+ it "should make a dirty repo clean" do
392
+ subject.should be_dirty
393
+ subject.reset_hard!
394
+ subject.should be_clean
395
+ end
396
+ end