librarianp 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +10 -0
  5. data/CHANGELOG.md +255 -0
  6. data/Gemfile +8 -0
  7. data/Gemfile.lock +235 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +55 -0
  10. data/Rakefile +28 -0
  11. data/VERSION +1 -0
  12. data/lib/librarian/action/base.rb +24 -0
  13. data/lib/librarian/action/clean.rb +44 -0
  14. data/lib/librarian/action/ensure.rb +24 -0
  15. data/lib/librarian/action/install.rb +95 -0
  16. data/lib/librarian/action/persist_resolution_mixin.rb +51 -0
  17. data/lib/librarian/action/resolve.rb +46 -0
  18. data/lib/librarian/action/update.rb +44 -0
  19. data/lib/librarian/action.rb +5 -0
  20. data/lib/librarian/algorithms.rb +133 -0
  21. data/lib/librarian/cli/manifest_presenter.rb +89 -0
  22. data/lib/librarian/cli.rb +225 -0
  23. data/lib/librarian/config/database.rb +205 -0
  24. data/lib/librarian/config/file_source.rb +47 -0
  25. data/lib/librarian/config/hash_source.rb +33 -0
  26. data/lib/librarian/config/source.rb +149 -0
  27. data/lib/librarian/config.rb +7 -0
  28. data/lib/librarian/dependency.rb +153 -0
  29. data/lib/librarian/dsl/receiver.rb +42 -0
  30. data/lib/librarian/dsl/target.rb +171 -0
  31. data/lib/librarian/dsl.rb +102 -0
  32. data/lib/librarian/environment/runtime_cache.rb +101 -0
  33. data/lib/librarian/environment.rb +230 -0
  34. data/lib/librarian/error.rb +4 -0
  35. data/lib/librarian/helpers.rb +29 -0
  36. data/lib/librarian/linter/source_linter.rb +55 -0
  37. data/lib/librarian/lockfile/compiler.rb +66 -0
  38. data/lib/librarian/lockfile/parser.rb +123 -0
  39. data/lib/librarian/lockfile.rb +29 -0
  40. data/lib/librarian/logger.rb +46 -0
  41. data/lib/librarian/manifest.rb +146 -0
  42. data/lib/librarian/manifest_set.rb +150 -0
  43. data/lib/librarian/mock/cli.rb +19 -0
  44. data/lib/librarian/mock/dsl.rb +15 -0
  45. data/lib/librarian/mock/environment.rb +21 -0
  46. data/lib/librarian/mock/extension.rb +9 -0
  47. data/lib/librarian/mock/source/mock/registry.rb +83 -0
  48. data/lib/librarian/mock/source/mock.rb +80 -0
  49. data/lib/librarian/mock/source.rb +1 -0
  50. data/lib/librarian/mock/version.rb +5 -0
  51. data/lib/librarian/mock.rb +1 -0
  52. data/lib/librarian/posix.rb +129 -0
  53. data/lib/librarian/resolution.rb +46 -0
  54. data/lib/librarian/resolver/implementation.rb +238 -0
  55. data/lib/librarian/resolver.rb +94 -0
  56. data/lib/librarian/rspec/support/cli_macro.rb +120 -0
  57. data/lib/librarian/source/basic_api.rb +45 -0
  58. data/lib/librarian/source/git/repository.rb +193 -0
  59. data/lib/librarian/source/git.rb +172 -0
  60. data/lib/librarian/source/local.rb +54 -0
  61. data/lib/librarian/source/path.rb +56 -0
  62. data/lib/librarian/source.rb +2 -0
  63. data/lib/librarian/spec.rb +13 -0
  64. data/lib/librarian/spec_change_set.rb +173 -0
  65. data/lib/librarian/specfile.rb +19 -0
  66. data/lib/librarian/support/abstract_method.rb +21 -0
  67. data/lib/librarian/ui.rb +64 -0
  68. data/lib/librarian/version.rb +3 -0
  69. data/lib/librarian.rb +11 -0
  70. data/librarian.gemspec +47 -0
  71. data/spec/functional/cli_spec.rb +27 -0
  72. data/spec/functional/posix_spec.rb +32 -0
  73. data/spec/functional/source/git/repository_spec.rb +199 -0
  74. data/spec/functional/source/git_spec.rb +174 -0
  75. data/spec/support/fakefs.rb +37 -0
  76. data/spec/support/method_patch_macro.rb +30 -0
  77. data/spec/support/project_path_macro.rb +14 -0
  78. data/spec/support/with_env_macro.rb +22 -0
  79. data/spec/unit/action/base_spec.rb +18 -0
  80. data/spec/unit/action/clean_spec.rb +102 -0
  81. data/spec/unit/action/ensure_spec.rb +37 -0
  82. data/spec/unit/action/install_spec.rb +111 -0
  83. data/spec/unit/algorithms_spec.rb +131 -0
  84. data/spec/unit/config/database_spec.rb +320 -0
  85. data/spec/unit/dependency/requirement_spec.rb +12 -0
  86. data/spec/unit/dependency_spec.rb +212 -0
  87. data/spec/unit/dsl_spec.rb +173 -0
  88. data/spec/unit/environment/runtime_cache_spec.rb +73 -0
  89. data/spec/unit/environment_spec.rb +209 -0
  90. data/spec/unit/lockfile/parser_spec.rb +162 -0
  91. data/spec/unit/lockfile_spec.rb +65 -0
  92. data/spec/unit/manifest/version_spec.rb +11 -0
  93. data/spec/unit/manifest_set_spec.rb +202 -0
  94. data/spec/unit/manifest_spec.rb +36 -0
  95. data/spec/unit/mock/environment_spec.rb +25 -0
  96. data/spec/unit/mock/source/mock_spec.rb +22 -0
  97. data/spec/unit/resolver_spec.rb +299 -0
  98. data/spec/unit/source/git_spec.rb +29 -0
  99. data/spec/unit/spec_change_set_spec.rb +169 -0
  100. metadata +257 -0
@@ -0,0 +1,64 @@
1
+ require 'rubygems/user_interaction'
2
+
3
+ module Librarian
4
+ class UI
5
+ def warn(message = nil)
6
+ end
7
+
8
+ def debug(message = nil)
9
+ end
10
+
11
+ def error(message = nil)
12
+ end
13
+
14
+ def info(message = nil)
15
+ end
16
+
17
+ def confirm(message = nil)
18
+ end
19
+
20
+ class Shell < UI
21
+ attr_writer :shell
22
+ attr_reader :debug_line_numbers
23
+
24
+ def initialize(shell)
25
+ @shell = shell
26
+ @quiet = false
27
+ @debug = ENV['DEBUG']
28
+ @debug_line_numbers = false
29
+ end
30
+
31
+ def debug(message = nil)
32
+ @shell.say(message || yield) if @debug && !@quiet
33
+ end
34
+
35
+ def info(message = nil)
36
+ @shell.say(message || yield) if !@quiet
37
+ end
38
+
39
+ def confirm(message = nil)
40
+ @shell.say(message || yield, :green) if !@quiet
41
+ end
42
+
43
+ def warn(message = nil)
44
+ @shell.say(message || yield, :yellow)
45
+ end
46
+
47
+ def error(message = nil)
48
+ @shell.say(message || yield, :red)
49
+ end
50
+
51
+ def be_quiet!
52
+ @quiet = true
53
+ end
54
+
55
+ def debug!
56
+ @debug = true
57
+ end
58
+
59
+ def debug_line_numbers!
60
+ @debug_line_numbers = true
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module Librarian
2
+ VERSION = File.read(File.expand_path("../../../VERSION", __FILE__)).strip
3
+ end
data/lib/librarian.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'librarian/version'
2
+ require 'librarian/environment'
3
+
4
+ module Librarian
5
+ extend self
6
+
7
+ def environment_class
8
+ self::Environment
9
+ end
10
+
11
+ end
data/librarian.gemspec ADDED
@@ -0,0 +1,47 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # stub: librarianp 0.1.2 ruby lib
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "librarianp"
6
+ s.version = "0.1.2"
7
+
8
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.require_paths = ["lib"]
10
+ s.authors = ["Jay Feldblum", "Carlos Sanchez"]
11
+ s.date = "2015-02-24"
12
+ s.description = "A Framework for Bundlers, used by librarian-puppet."
13
+ s.email = ["y_feldblum@yahoo.com", "carlos@apache.org"]
14
+ s.files = [".gitignore", ".rspec", ".travis.yml", "CHANGELOG.md", "Gemfile", "Gemfile.lock", "LICENSE.txt", "README.md", "Rakefile", "VERSION", "lib/librarian.rb", "lib/librarian/action.rb", "lib/librarian/action/base.rb", "lib/librarian/action/clean.rb", "lib/librarian/action/ensure.rb", "lib/librarian/action/install.rb", "lib/librarian/action/persist_resolution_mixin.rb", "lib/librarian/action/resolve.rb", "lib/librarian/action/update.rb", "lib/librarian/algorithms.rb", "lib/librarian/cli.rb", "lib/librarian/cli/manifest_presenter.rb", "lib/librarian/config.rb", "lib/librarian/config/database.rb", "lib/librarian/config/file_source.rb", "lib/librarian/config/hash_source.rb", "lib/librarian/config/source.rb", "lib/librarian/dependency.rb", "lib/librarian/dsl.rb", "lib/librarian/dsl/receiver.rb", "lib/librarian/dsl/target.rb", "lib/librarian/environment.rb", "lib/librarian/environment/runtime_cache.rb", "lib/librarian/error.rb", "lib/librarian/helpers.rb", "lib/librarian/linter/source_linter.rb", "lib/librarian/lockfile.rb", "lib/librarian/lockfile/compiler.rb", "lib/librarian/lockfile/parser.rb", "lib/librarian/logger.rb", "lib/librarian/manifest.rb", "lib/librarian/manifest_set.rb", "lib/librarian/mock.rb", "lib/librarian/mock/cli.rb", "lib/librarian/mock/dsl.rb", "lib/librarian/mock/environment.rb", "lib/librarian/mock/extension.rb", "lib/librarian/mock/source.rb", "lib/librarian/mock/source/mock.rb", "lib/librarian/mock/source/mock/registry.rb", "lib/librarian/mock/version.rb", "lib/librarian/posix.rb", "lib/librarian/resolution.rb", "lib/librarian/resolver.rb", "lib/librarian/resolver/implementation.rb", "lib/librarian/rspec/support/cli_macro.rb", "lib/librarian/source.rb", "lib/librarian/source/basic_api.rb", "lib/librarian/source/git.rb", "lib/librarian/source/git/repository.rb", "lib/librarian/source/local.rb", "lib/librarian/source/path.rb", "lib/librarian/spec.rb", "lib/librarian/spec_change_set.rb", "lib/librarian/specfile.rb", "lib/librarian/support/abstract_method.rb", "lib/librarian/ui.rb", "lib/librarian/version.rb", "librarian.gemspec", "spec/functional/cli_spec.rb", "spec/functional/posix_spec.rb", "spec/functional/source/git/repository_spec.rb", "spec/functional/source/git_spec.rb", "spec/support/fakefs.rb", "spec/support/method_patch_macro.rb", "spec/support/project_path_macro.rb", "spec/support/with_env_macro.rb", "spec/unit/action/base_spec.rb", "spec/unit/action/clean_spec.rb", "spec/unit/action/ensure_spec.rb", "spec/unit/action/install_spec.rb", "spec/unit/algorithms_spec.rb", "spec/unit/config/database_spec.rb", "spec/unit/dependency/requirement_spec.rb", "spec/unit/dependency_spec.rb", "spec/unit/dsl_spec.rb", "spec/unit/environment/runtime_cache_spec.rb", "spec/unit/environment_spec.rb", "spec/unit/lockfile/parser_spec.rb", "spec/unit/lockfile_spec.rb", "spec/unit/manifest/version_spec.rb", "spec/unit/manifest_set_spec.rb", "spec/unit/manifest_spec.rb", "spec/unit/mock/environment_spec.rb", "spec/unit/mock/source/mock_spec.rb", "spec/unit/resolver_spec.rb", "spec/unit/source/git_spec.rb", "spec/unit/spec_change_set_spec.rb"]
15
+ s.homepage = "https://github.com/carlossg/librarian"
16
+ s.licenses = ["MIT"]
17
+ s.rubygems_version = "2.4.3"
18
+ s.summary = "A Framework for Bundlers."
19
+ s.test_files = ["spec/functional/cli_spec.rb", "spec/functional/posix_spec.rb", "spec/functional/source/git/repository_spec.rb", "spec/functional/source/git_spec.rb", "spec/support/fakefs.rb", "spec/support/method_patch_macro.rb", "spec/support/project_path_macro.rb", "spec/support/with_env_macro.rb", "spec/unit/action/base_spec.rb", "spec/unit/action/clean_spec.rb", "spec/unit/action/ensure_spec.rb", "spec/unit/action/install_spec.rb", "spec/unit/algorithms_spec.rb", "spec/unit/config/database_spec.rb", "spec/unit/dependency/requirement_spec.rb", "spec/unit/dependency_spec.rb", "spec/unit/dsl_spec.rb", "spec/unit/environment/runtime_cache_spec.rb", "spec/unit/environment_spec.rb", "spec/unit/lockfile/parser_spec.rb", "spec/unit/lockfile_spec.rb", "spec/unit/manifest/version_spec.rb", "spec/unit/manifest_set_spec.rb", "spec/unit/manifest_spec.rb", "spec/unit/mock/environment_spec.rb", "spec/unit/mock/source/mock_spec.rb", "spec/unit/resolver_spec.rb", "spec/unit/source/git_spec.rb", "spec/unit/spec_change_set_spec.rb"]
20
+
21
+ if s.respond_to? :specification_version then
22
+ s.specification_version = 4
23
+
24
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
+ s.add_runtime_dependency(%q<thor>, ["~> 0.15"])
26
+ s.add_runtime_dependency(%q<highline>, [">= 0"])
27
+ s.add_development_dependency(%q<rake>, [">= 0"])
28
+ s.add_development_dependency(%q<rspec>, ["~> 2.14"])
29
+ s.add_development_dependency(%q<json>, [">= 0"])
30
+ s.add_development_dependency(%q<fakefs>, ["~> 0.4.2"])
31
+ else
32
+ s.add_dependency(%q<thor>, ["~> 0.15"])
33
+ s.add_dependency(%q<highline>, [">= 0"])
34
+ s.add_dependency(%q<rake>, [">= 0"])
35
+ s.add_dependency(%q<rspec>, ["~> 2.14"])
36
+ s.add_dependency(%q<json>, [">= 0"])
37
+ s.add_dependency(%q<fakefs>, ["~> 0.4.2"])
38
+ end
39
+ else
40
+ s.add_dependency(%q<thor>, ["~> 0.15"])
41
+ s.add_dependency(%q<highline>, [">= 0"])
42
+ s.add_dependency(%q<rake>, [">= 0"])
43
+ s.add_dependency(%q<rspec>, ["~> 2.14"])
44
+ s.add_dependency(%q<json>, [">= 0"])
45
+ s.add_dependency(%q<fakefs>, ["~> 0.4.2"])
46
+ end
47
+ end
@@ -0,0 +1,27 @@
1
+ require "securerandom"
2
+
3
+ require "librarian/rspec/support/cli_macro"
4
+
5
+ require "librarian/mock/cli"
6
+
7
+ module Librarian
8
+ module Mock
9
+ describe Cli do
10
+ include Librarian::RSpec::Support::CliMacro
11
+
12
+ describe "version" do
13
+ before do
14
+ cli! "version"
15
+ end
16
+
17
+ it "should print the version" do
18
+ expect(stdout).to eq strip_heredoc(<<-STDOUT)
19
+ librarian-#{Librarian::VERSION}
20
+ librarian-mock-#{Librarian::Mock::VERSION}
21
+ STDOUT
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ require "librarian/posix"
2
+
3
+ require "support/project_path_macro"
4
+
5
+ describe Librarian::Posix do
6
+ include Support::ProjectPathMacro
7
+
8
+ let(:tmp_path) { project_path + "tmp/spec/functional/posix" }
9
+ after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
10
+
11
+ describe ".run!" do
12
+
13
+ it "returns the stdout" do
14
+ res = described_class.run!(%w[echo hello there]).strip
15
+ expect(res).to eq "hello there"
16
+ end
17
+
18
+ it "changes directory" do
19
+ tmp_path.mkpath
20
+ res = described_class.run!(%w[pwd], :chdir => tmp_path).strip
21
+ expect(res).to eq tmp_path.to_s
22
+ end
23
+
24
+ it "reads the env" do
25
+ res = described_class.run!(%w[env], :env => {"KOALA" => "BEAR"})
26
+ line = res.lines.find{|l| l.start_with?("KOALA=")}.strip
27
+ expect(line).to eq "KOALA=BEAR"
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,199 @@
1
+ require "fileutils"
2
+ require "pathname"
3
+ require "securerandom"
4
+
5
+ require "librarian/posix"
6
+
7
+ require "librarian/source/git/repository"
8
+
9
+ require "librarian/mock/environment"
10
+
11
+ require "support/project_path_macro"
12
+
13
+ describe Librarian::Source::Git::Repository do
14
+ include Support::ProjectPathMacro
15
+
16
+ let(:env) { Librarian::Mock::Environment.new }
17
+
18
+ let(:tmp_path) { project_path + "tmp/spec/functional/source/git/repository" }
19
+ after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
20
+ let(:git_source_path) { tmp_path + SecureRandom.hex(16) }
21
+ let(:branch) { "the-branch" }
22
+ let(:tag) { "the-tag" }
23
+ let(:atag) { "the-atag" }
24
+
25
+ def cmd!(command)
26
+ Librarian::Posix.run! command
27
+ end
28
+
29
+ def git!(command)
30
+ cmd!([described_class.bin] + command)
31
+ end
32
+
33
+ before do
34
+ git_source_path.mkpath
35
+ Dir.chdir(git_source_path) do
36
+ git! %W[init]
37
+ git! %W[config user.name Simba]
38
+ git! %W[config user.email simba@savannah-pride.gov]
39
+
40
+ # master
41
+ FileUtils.touch "butter.txt"
42
+ git! %W[add butter.txt]
43
+ git! %W[commit -m #{"Initial Commit"}]
44
+
45
+ # branch
46
+ git! %W[checkout -b #{branch} --quiet]
47
+ FileUtils.touch "jam.txt"
48
+ git! %W[add jam.txt]
49
+ git! %W[commit -m #{"Branch Commit"}]
50
+ git! %W[checkout master --quiet]
51
+
52
+ # tag/atag
53
+ git! %W[checkout -b deletable --quiet]
54
+ FileUtils.touch "jelly.txt"
55
+ git! %W[add jelly.txt]
56
+ git! %W[commit -m #{"Tag Commit"}]
57
+ git! %W[tag #{tag}]
58
+ git! %W[tag -am #{"Annotated Tag Commit"} #{atag}]
59
+ git! %W[checkout master --quiet]
60
+ git! %W[branch -D deletable]
61
+ end
62
+ end
63
+
64
+ describe ".bin" do
65
+ specify { expect(described_class.bin).to_not be_empty }
66
+ end
67
+
68
+ describe ".git_version" do
69
+ specify { expect(described_class.git_version).to match( /^\d+(\.\d+)+$/ ) }
70
+ end
71
+
72
+ context "the original" do
73
+ subject { described_class.new(env, git_source_path) }
74
+
75
+ it "should recognize it" do
76
+ expect(subject).to be_git
77
+ end
78
+
79
+ it "should not list any remotes for it" do
80
+ expect(subject.remote_names).to be_empty
81
+ end
82
+
83
+ it "should not list any remote branches for it" do
84
+ expect(subject.remote_branch_names).to be_empty
85
+ end
86
+
87
+ it "should have divergent shas for master, branch, tag, and atag" do
88
+ revs = %W[ master #{branch} #{tag} #{atag} ]
89
+ rev_parse = proc{|rev| git!(%W[rev-parse #{rev} --quiet]).strip}
90
+ shas = Dir.chdir(git_source_path){revs.map(&rev_parse)}
91
+ expect(shas.map(&:class).uniq).to eq [String]
92
+ expect(shas.map(&:size).uniq).to eq [40]
93
+ expect(shas.uniq).to eq shas
94
+ end
95
+ end
96
+
97
+ context "a clone" do
98
+ let(:git_clone_path) { tmp_path + SecureRandom.hex(16) }
99
+ subject { described_class.clone!(env, git_clone_path, git_source_path) }
100
+
101
+ let(:master_sha) { subject.hash_from("origin", "master") }
102
+ let(:branch_sha) { subject.hash_from("origin", branch) }
103
+ let(:tag_sha) { subject.hash_from("origin", tag) }
104
+ let(:atag_sha) { subject.hash_from("origin", atag) }
105
+
106
+ it "should recognize it" do
107
+ expect(subject).to be_git
108
+ end
109
+
110
+ it "should have a single remote for it" do
111
+ expect(subject).to have(1).remote_names
112
+ end
113
+
114
+ it "should have a remote with the expected name" do
115
+ expect(subject.remote_names.first).to eq "origin"
116
+ end
117
+
118
+ it "should have the remote branch" do
119
+ expect(subject.remote_branch_names["origin"]).to include branch
120
+ end
121
+
122
+ it "should be checked out on the master" do
123
+ expect(subject).to be_checked_out(master_sha)
124
+ end
125
+
126
+ context "checking for commits" do
127
+ it "has the master commit" do
128
+ expect(subject).to have_commit(master_sha)
129
+ end
130
+
131
+ it "has the branch commit" do
132
+ expect(subject).to have_commit(branch_sha)
133
+ end
134
+
135
+ it "has the tag commit" do
136
+ expect(subject).to have_commit(tag_sha)
137
+ end
138
+
139
+ it "has the atag commit" do
140
+ expect(subject).to have_commit(atag_sha)
141
+ end
142
+
143
+ it "does not have a made-up commit" do
144
+ expect(subject).to_not have_commit(SecureRandom.hex(20))
145
+ end
146
+
147
+ it "does not have a tree commit" do
148
+ master_tree_sha = Dir.chdir(git_source_path) do
149
+ git!(%W[log -1 --no-color --format=tformat:%T master]).strip
150
+ end
151
+ expect(master_tree_sha).to match(/\A[0-9a-f]{40}\z/) # sanity
152
+ expect(subject).to_not have_commit(master_tree_sha)
153
+ end
154
+ end
155
+
156
+ context "checking out the branch" do
157
+ before do
158
+ subject.checkout! branch
159
+ end
160
+
161
+ it "should be checked out on the branch" do
162
+ expect(subject).to be_checked_out(branch_sha)
163
+ end
164
+
165
+ it "should not be checked out on the master" do
166
+ expect(subject).to_not be_checked_out(master_sha)
167
+ end
168
+ end
169
+
170
+ context "checking out the tag" do
171
+ before do
172
+ subject.checkout! tag
173
+ end
174
+
175
+ it "should be checked out on the tag" do
176
+ expect(subject).to be_checked_out(tag_sha)
177
+ end
178
+
179
+ it "should not be checked out on the master" do
180
+ expect(subject).to_not be_checked_out(master_sha)
181
+ end
182
+ end
183
+
184
+ context "checking out the annotated tag" do
185
+ before do
186
+ subject.checkout! atag
187
+ end
188
+
189
+ it "should be checked out on the annotated tag" do
190
+ expect(subject).to be_checked_out(atag_sha)
191
+ end
192
+
193
+ it "should not be checked out on the master" do
194
+ expect(subject).to_not be_checked_out(master_sha)
195
+ end
196
+ end
197
+ end
198
+
199
+ end
@@ -0,0 +1,174 @@
1
+ require "fileutils"
2
+ require "pathname"
3
+ require "securerandom"
4
+
5
+ require "librarian/error"
6
+ require "librarian/posix"
7
+ require "librarian/source/git"
8
+ require "librarian/source/git/repository"
9
+ require "librarian/mock/environment"
10
+
11
+ require "support/project_path_macro"
12
+
13
+ describe Librarian::Source::Git do
14
+ include Support::ProjectPathMacro
15
+
16
+ let(:tmp_path) { project_path + "tmp/spec/functional/source/git" }
17
+ after { tmp_path.rmtree if tmp_path && tmp_path.exist? }
18
+ let(:env_project_path) { tmp_path + "project" }
19
+
20
+ def cmd!(command)
21
+ Librarian::Posix.run! command
22
+ end
23
+
24
+ def git!(command)
25
+ cmd!([Librarian::Source::Git::Repository.bin] + command)
26
+ end
27
+
28
+ def new_env
29
+ Librarian::Mock::Environment.new(:project_path => env_project_path)
30
+ end
31
+
32
+ context "when the remote is bad" do
33
+ let(:remote) { tmp_path.join(SecureRandom.hex(8)).to_s }
34
+ let(:env) { new_env }
35
+ let(:source) { described_class.new(env, remote, {}) }
36
+
37
+ it "fails when caching" do
38
+ expect { source.cache! }.to raise_error Librarian::Error,
39
+ /^fatal: repository .+ does not exist$/ # from git
40
+ end
41
+ end
42
+
43
+ context "when the remote has a repo" do
44
+ let(:remote) { tmp_path.join(SecureRandom.hex(8)).to_s }
45
+ let(:git_source_path) { Pathname.new(remote) }
46
+ let(:env) { new_env }
47
+ let(:source) { described_class.new(env, remote, {}) }
48
+
49
+ before do
50
+ git_source_path.mkpath
51
+ Dir.chdir(git_source_path) do
52
+ git! %W[init]
53
+ git! %W[config user.name Simba]
54
+ git! %W[config user.email simba@savannah-pride.gov]
55
+ FileUtils.touch "butter.txt"
56
+ git! %W[add butter.txt]
57
+ git! %W[commit -m #{"Initial Commit"}]
58
+ end
59
+ end
60
+
61
+ let(:sha) do
62
+ Dir.chdir(git_source_path) do
63
+ git!(%W[rev-parse master]).strip
64
+ end
65
+ end
66
+
67
+ context "when caching once" do
68
+ it "has the expected sha" do
69
+ expect{source.cache!}.to change{source.sha}.from(nil).to(sha)
70
+ end
71
+
72
+ it "records the history" do
73
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(9)
74
+ end
75
+ end
76
+
77
+ context "when caching twice" do
78
+ before { source.cache! }
79
+
80
+ it "keeps the expected sha" do
81
+ expect{source.cache!}.to_not change{source.sha}
82
+ end
83
+
84
+ it "runs git commands once" do
85
+ expect{source.cache!}.to_not change{source.git_ops_count}
86
+ end
87
+ end
88
+
89
+ context "when caching twice from different sources" do
90
+ let(:other_source) { described_class.new(env, remote, {}) }
91
+ before { other_source.cache! }
92
+
93
+ it "has the expected sha" do
94
+ expect{source.cache!}.to change{source.sha}.from(nil).to(sha)
95
+ end
96
+
97
+ it "records the history" do
98
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(1)
99
+ end
100
+ end
101
+
102
+ context "when caching twice from different sources, second time with sha" do
103
+ let(:other_source) { described_class.new(env, remote, {}) }
104
+ before { other_source.cache! }
105
+
106
+ let(:source) { described_class.new(env, remote, {:sha => sha}) }
107
+
108
+ it "has the expected sha" do
109
+ expect{source.cache!}.to_not change{source.sha}
110
+ end
111
+
112
+ it "records the history" do
113
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(1)
114
+ end
115
+ end
116
+
117
+ context "when caching twice from different environments" do
118
+ let(:other_source) { described_class.new(new_env, remote, {}) }
119
+ before { other_source.cache! }
120
+
121
+ it "has the expected sha" do
122
+ expect{source.cache!}.to change{source.sha}.from(nil).to(sha)
123
+ end
124
+
125
+ it "records the history" do
126
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(8)
127
+ end
128
+ end
129
+
130
+ context "when caching twice from different environments, second time with sha" do
131
+ let(:other_source) { described_class.new(new_env, remote, {}) }
132
+ before { other_source.cache! }
133
+
134
+ let(:source) { described_class.new(env, remote, {:sha => sha}) }
135
+
136
+ it "has the expected sha" do
137
+ expect{source.cache!}.to_not change{source.sha}
138
+ end
139
+
140
+ it "records the history" do
141
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(3)
142
+ end
143
+ end
144
+
145
+ context "when the sha is missing from a cached repo" do
146
+ let(:other_source) { described_class.new(new_env, remote, {}) }
147
+ before { other_source.cache! }
148
+
149
+ before do
150
+ Dir.chdir(git_source_path) do
151
+ FileUtils.touch "jam.txt"
152
+ git! %w[add jam.txt]
153
+ git! %W[commit -m #{"Some Jam"}]
154
+ end
155
+ end
156
+
157
+ let(:source) { described_class.new(env, remote, {:sha => sha}) }
158
+
159
+ it "has a new remote sha" do
160
+ expect(sha).to_not eq(other_source.sha)
161
+ end
162
+
163
+ it "has the expected sha" do
164
+ expect{source.cache!}.to_not change{source.sha}
165
+ end
166
+
167
+ it "records the history" do
168
+ expect{source.cache!}.to change{source.git_ops_count}.from(0).to(8)
169
+ end
170
+ end
171
+
172
+ end
173
+
174
+ end
@@ -0,0 +1,37 @@
1
+ require "fakefs/safe"
2
+ require "fakefs/spec_helpers"
3
+ require "support/method_patch_macro"
4
+
5
+ if defined?(Rubinius)
6
+ module Rubinius
7
+ class CodeLoader
8
+ class << self
9
+ alias_method :require_fakefs_original, :require
10
+ def require(s)
11
+ ::FakeFS.without { require_fakefs_original(s) }
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ module Support
19
+ module FakeFS
20
+
21
+ def self.included(base)
22
+ base.module_exec do
23
+ include ::FakeFS::SpecHelpers
24
+ end
25
+
26
+ # Since ruby-1.9.3-p286, Kernel#Pathname was changed in a way that broke
27
+ # FakeFS's assumptions. It used to lookup the Pathname constant (which is
28
+ # where FakeFS hooks) and send it #new, but now it keeps a reference to
29
+ # the Pathname constant (breaking the FakeFS hook).
30
+ base.module_exec do
31
+ include MethodPatchMacro
32
+ with_module_method(Kernel, :Pathname){|s| Pathname.new(s)}
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,30 @@
1
+ require "securerandom"
2
+
3
+ module Support
4
+ module MethodPatchMacro
5
+
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def with_module_method(mod, meth, &block)
12
+ tag = SecureRandom.hex(8)
13
+ orig_meth = "_#{tag}_#{meth}".to_sym
14
+ before do
15
+ mod.module_eval do
16
+ alias_method orig_meth, meth
17
+ define_method meth, &block
18
+ end
19
+ end
20
+ after do
21
+ mod.module_eval do
22
+ alias_method meth, orig_meth
23
+ remove_method orig_meth
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,14 @@
1
+ module Support
2
+ module ProjectPathMacro
3
+
4
+ project_path = Pathname.new(__FILE__).expand_path
5
+ project_path = project_path.dirname until project_path.join("Rakefile").exist?
6
+
7
+ PROJECT_PATH = project_path
8
+
9
+ def project_path
10
+ PROJECT_PATH
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ module Support
2
+ module WithEnvMacro
3
+
4
+ module ClassMethods
5
+
6
+ def with_env(new)
7
+ old = Hash[new.map{|k, v| [k, ENV[k]]}]
8
+
9
+ before { ENV.update(new) }
10
+ after { ENV.update(old) }
11
+ end
12
+
13
+ end
14
+
15
+ private
16
+
17
+ def self.included(base)
18
+ base.extend(ClassMethods)
19
+ end
20
+
21
+ end
22
+ end