puppet-library 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.yml +11 -0
  3. data/README.md +16 -7
  4. data/Rakefile +21 -21
  5. data/TODO.yml +10 -6
  6. data/bin/puppet-library +0 -1
  7. data/config.ru +14 -16
  8. data/features/step_definitions/sinatra_steps.rb +3 -12
  9. data/lib/puppet_library/forge.rb +1 -0
  10. data/lib/puppet_library/forge/abstract.rb +2 -1
  11. data/lib/puppet_library/forge/cache.rb +11 -7
  12. data/lib/puppet_library/forge/directory.rb +15 -13
  13. data/lib/puppet_library/forge/forge.rb +25 -0
  14. data/lib/puppet_library/forge/git_repository.rb +42 -17
  15. data/lib/puppet_library/forge/multi.rb +11 -1
  16. data/lib/puppet_library/forge/proxy.rb +14 -9
  17. data/lib/puppet_library/forge/source.rb +12 -13
  18. data/lib/puppet_library/http/cache/disk.rb +26 -8
  19. data/lib/puppet_library/http/cache/in_memory.rb +13 -10
  20. data/lib/puppet_library/http/cache/noop.rb +4 -1
  21. data/lib/puppet_library/puppet_library.rb +10 -7
  22. data/lib/puppet_library/puppet_module/modulefile.rb +5 -1
  23. data/lib/puppet_library/server.rb +13 -9
  24. data/lib/puppet_library/util.rb +1 -0
  25. data/lib/puppet_library/util/config_api.rb +115 -0
  26. data/lib/puppet_library/util/git.rb +36 -8
  27. data/lib/puppet_library/util/logging.rb +49 -0
  28. data/lib/puppet_library/util/patches.rb +21 -0
  29. data/lib/puppet_library/util/temp_dir.rb +20 -5
  30. data/lib/puppet_library/version.rb +1 -1
  31. data/puppet-library.gemspec +2 -0
  32. data/spec/archive/archive_reader_spec.rb +2 -6
  33. data/spec/archive/archiver_spec.rb +5 -9
  34. data/spec/forge/cache_spec.rb +13 -7
  35. data/spec/forge/directory_spec.rb +31 -18
  36. data/spec/forge/git_repository_spec.rb +60 -13
  37. data/spec/forge/multi_spec.rb +16 -0
  38. data/spec/forge/proxy_spec.rb +18 -0
  39. data/spec/forge/source_spec.rb +14 -9
  40. data/spec/http/cache/disk_spec.rb +11 -6
  41. data/spec/http/cache/in_memory_spec.rb +12 -0
  42. data/spec/http/cache/noop_spec.rb +6 -0
  43. data/spec/integration_test_helper.rb +3 -3
  44. data/spec/module_spec_helper.rb +2 -2
  45. data/spec/puppet_library_spec.rb +34 -16
  46. data/spec/puppet_module/modulefile_spec.rb +48 -9
  47. data/spec/server_spec.rb +28 -1
  48. data/spec/spec_helper.rb +2 -14
  49. data/spec/util/config_api_spec.rb +77 -0
  50. data/spec/util/git_spec.rb +20 -20
  51. data/spec/util/patches_spec.rb +18 -0
  52. data/test/directory_forge_integration_test.rb +6 -8
  53. data/test/offline_git_repo_forge_integration_test.rb +9 -14
  54. data/test/offline_proxy_forge_integration_test.rb +11 -14
  55. data/test/online_git_repo_forge_integration_test.rb +7 -8
  56. data/test/online_proxy_forge_integration_test.rb +10 -13
  57. data/test/source_forge_integration_test.rb +7 -8
  58. metadata +35 -2
@@ -17,16 +17,20 @@
17
17
  require 'fileutils'
18
18
  require 'monitor'
19
19
  require 'time'
20
+ require 'open4'
21
+ require 'puppet_library/util/logging'
20
22
  require 'puppet_library/util/temp_dir'
21
23
 
22
24
  module PuppetLibrary::Util
23
25
  class Git
26
+ include Logging
27
+
24
28
  DEFAULT_CACHE_TTL_SECONDS = 60
25
- def initialize(source, cache_path, cache_ttl_seconds = DEFAULT_CACHE_TTL_SECONDS)
29
+ def initialize(source, cache_dir, cache_ttl_seconds = DEFAULT_CACHE_TTL_SECONDS)
26
30
  @source = source
27
- @cache_path = File.expand_path(cache_path)
31
+ @cache_dir = cache_dir
28
32
  @cache_ttl_seconds = cache_ttl_seconds
29
- @git_dir = File.join(@cache_path, ".git")
33
+ @git_dir = File.join(@cache_dir.path, ".git")
30
34
  @mutex = Monitor.new
31
35
  end
32
36
 
@@ -48,9 +52,17 @@ module PuppetLibrary::Util
48
52
  git "show refs/tags/#{tag}:#{path}"
49
53
  end
50
54
 
55
+ def file_exists?(path, tag)
56
+ read_file(path, tag)
57
+ true
58
+ rescue GitCommandError
59
+ false
60
+ end
61
+
51
62
  def clear_cache!
52
63
  @mutex.synchronize do
53
- FileUtils.rm_rf @cache_path
64
+ info "Clearing cache for Git repository #{@source} from #{@git_dir}"
65
+ FileUtils.rm_rf @cache_dir.path
54
66
  end
55
67
  end
56
68
 
@@ -62,7 +74,8 @@ module PuppetLibrary::Util
62
74
  private
63
75
  def create_cache
64
76
  @mutex.synchronize do
65
- git "clone --bare #{@source} #{@git_dir}" unless cache_exists?
77
+ info "Cloning Git repository from #{@source} to #{@git_dir}"
78
+ git "clone --bare #{@source} #{@git_dir}"
66
79
  FileUtils.touch fetch_file
67
80
  end
68
81
  end
@@ -94,10 +107,25 @@ module PuppetLibrary::Util
94
107
  end
95
108
 
96
109
  def git(command, work_tree = nil)
97
- work_tree = @cache_path unless work_tree
98
- Open3.popen3("git --git-dir=#{@git_dir} --work-tree=#{work_tree} #{command}") do |stdin, stdout, stderr, thread|
99
- stdout.read
110
+ work_tree = @cache_dir.path unless work_tree
111
+ run "git --git-dir=#{@git_dir} --work-tree=#{work_tree} #{command}"
112
+ end
113
+
114
+ def run(command)
115
+ debug command
116
+ pid, stdin, stdout, stderr = Open4.popen4(command)
117
+ ignored, status = Process::waitpid2 pid
118
+ unless status.success?
119
+ raise GitCommandError, "Error running Git command: #{command}\n#{stdout.read}\n#{stderr.read}"
100
120
  end
121
+ stdout.read
122
+ ensure
123
+ stdin.close
124
+ stdout.close
125
+ stderr.close
126
+ end
127
+
128
+ class GitCommandError < StandardError
101
129
  end
102
130
  end
103
131
  end
@@ -0,0 +1,49 @@
1
+ # Puppet Library
2
+ # Copyright (C) 2014 drrb
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'logger'
18
+
19
+ module PuppetLibrary::Util
20
+ module Logging
21
+ def log_io
22
+ @log_io ||= StringIO.new
23
+ end
24
+
25
+ def logger
26
+ destination = ENV["TESTING"] ? log_io : STDERR
27
+ @logger ||= Logger.new(destination).tap do |logger|
28
+ logger.progname = self.class.name
29
+ logger.level = Logger::DEBUG
30
+ end
31
+ end
32
+
33
+ def debug(message)
34
+ logger.debug message
35
+ end
36
+
37
+ def info(message)
38
+ logger.info message
39
+ end
40
+
41
+ def warn(message)
42
+ logger.warn message
43
+ end
44
+
45
+ #def error(message)
46
+ # logger.error message
47
+ #end
48
+ end
49
+ end
@@ -78,6 +78,15 @@ class Array
78
78
  merged.deep_merge(map)
79
79
  end
80
80
  end
81
+
82
+ def each_in_parallel
83
+ threads = map do |element|
84
+ Thread.new do
85
+ yield(element)
86
+ end
87
+ end
88
+ threads.each &:join
89
+ end
81
90
  end
82
91
 
83
92
  class Hash
@@ -92,6 +101,12 @@ class Hash
92
101
  end
93
102
  end
94
103
 
104
+ class String
105
+ def snake_case_to_camel_case
106
+ split("_").map(&:capitalize).join
107
+ end
108
+ end
109
+
95
110
  class Gem::Package::TarReader
96
111
  # Old versions of RubyGems don't include Enumerable in here
97
112
  def find
@@ -102,3 +117,9 @@ class Gem::Package::TarReader
102
117
  end
103
118
  end
104
119
  end
120
+
121
+ class Dir
122
+ def to_str
123
+ path
124
+ end
125
+ end
@@ -29,14 +29,29 @@ module PuppetLibrary::Util
29
29
  end
30
30
 
31
31
  def self.create(name)
32
- TempDir.new(name).path
32
+ file = Tempfile.new(name)
33
+ path = file.path
34
+ file.unlink
35
+ FileUtils.mkdir path
36
+ path
33
37
  end
34
38
 
35
39
  def initialize(name)
36
- file = Tempfile.new(name)
37
- @path = file.path
38
- file.unlink
39
- FileUtils.mkdir @path
40
+ @path = TempDir.create(name)
41
+ @remover = Remover.new(@path)
42
+ ObjectSpace.define_finalizer(self, @remover)
43
+ end
44
+
45
+ class Remover
46
+ def initialize(path)
47
+ @path = path
48
+ end
49
+
50
+ def call(*args)
51
+ if File.directory? @path
52
+ FileUtils.rm_rf @path
53
+ end
54
+ end
40
55
  end
41
56
  end
42
57
  end
@@ -16,5 +16,5 @@
16
16
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
 
18
18
  module PuppetLibrary
19
- VERSION = "0.10.0"
19
+ VERSION = "0.11.0"
20
20
  end
@@ -39,6 +39,8 @@ Gem::Specification.new do |spec|
39
39
  spec.add_dependency "sinatra"
40
40
  spec.add_dependency "json"
41
41
  spec.add_dependency "haml"
42
+ spec.add_dependency "docile", ">= 1.0.0"
43
+ spec.add_dependency "open4"
42
44
 
43
45
  spec.add_development_dependency "bundler", "~> 1.3"
44
46
  spec.add_development_dependency "coveralls"
@@ -23,11 +23,11 @@ module PuppetLibrary::Archive
23
23
  end
24
24
 
25
25
  let :source_dir do
26
- Tempdir.create("zipping")
26
+ Tempdir.new("zipping")
27
27
  end
28
28
 
29
29
  let :archive do
30
- archive = File.join(source_dir, "archive.tgz")
30
+ archive = File.join(source_dir.path, "archive.tgz")
31
31
  write_tar_gzip!(archive) do |zip|
32
32
  zip.add_file("arrive.txt", 0644) { |entry| entry.write "say hello" }
33
33
  zip.add_file("later/depart.txt", 0644) { |entry| entry.write "say bye" }
@@ -35,10 +35,6 @@ module PuppetLibrary::Archive
35
35
  archive
36
36
  end
37
37
 
38
- after do
39
- rm_rf source_dir
40
- end
41
-
42
38
  def write_tar_gzip!(file_name)
43
39
  tar = StringIO.new
44
40
 
@@ -19,10 +19,10 @@ require 'spec_helper'
19
19
  module PuppetLibrary::Archive
20
20
  describe Archiver do
21
21
  describe "#archive_dir" do
22
- let(:dir) { Tempdir.create("tozip") }
22
+ let(:dir) { Tempdir.new("tozip") }
23
23
 
24
24
  def write_file!(filename, content)
25
- path = File.join(dir, filename)
25
+ path = File.join(dir.path, filename)
26
26
  FileUtils.mkdir_p(File.dirname(path))
27
27
  File.open(path, "w") do |file|
28
28
  file.write content
@@ -34,19 +34,15 @@ module PuppetLibrary::Archive
34
34
  write_file! "later/depart.txt", "say bye"
35
35
  end
36
36
 
37
- after do
38
- rm_rf dir
39
- end
40
-
41
37
  it "tars and gzips a directory and its contents" do
42
- buffer = Archiver.archive_dir(dir, "todo")
38
+ buffer = Archiver.archive_dir(dir.path, "todo")
43
39
 
44
40
  expect(buffer).to be_tgz_with "todo/arrive.txt", "say hello"
45
41
  expect(buffer).to be_tgz_with "todo/later/depart.txt", "say bye"
46
42
  end
47
43
 
48
44
  it "allows you to inject files from a block" do
49
- buffer = Archiver.archive_dir(dir, "todo") do |archive|
45
+ buffer = Archiver.archive_dir(dir.path, "todo") do |archive|
50
46
  archive.add_file("later/return.txt", 0644) do |entry|
51
47
  entry.write "say hi again"
52
48
  end
@@ -56,7 +52,7 @@ module PuppetLibrary::Archive
56
52
  end
57
53
 
58
54
  it "fixes leading slash for adding files" do
59
- buffer = Archiver.archive_dir(dir, "todo") do |archive|
55
+ buffer = Archiver.archive_dir(dir.path, "todo") do |archive|
60
56
  archive.add_file("/later/return.txt", 0644) do |entry|
61
57
  entry.write "say hi again"
62
58
  end
@@ -19,18 +19,24 @@ require 'spec_helper'
19
19
 
20
20
  module PuppetLibrary::Forge
21
21
  describe Cache do
22
- let(:cache_dir) { Tempdir.create("module-cache") }
22
+ let(:cache_dir) { Tempdir.new("module-cache") }
23
23
  let(:http_client) { double(PuppetLibrary::Http::HttpClient) }
24
24
  let(:forge) { Cache.new("http://forge.example.com", cache_dir, http_client) }
25
25
 
26
- after do
27
- rm_rf cache_dir
28
- end
29
-
30
26
  it "is a proxy" do
31
27
  expect(forge).to be_a Proxy
32
28
  end
33
29
 
30
+ describe "#configure" do
31
+ it "exposes a configuration API" do
32
+ forge = Cache.configure do
33
+ url "http://example.com"
34
+ path cache_dir.path
35
+ end
36
+ expect(forge.instance_eval "@url").to eq "http://example.com"
37
+ end
38
+ end
39
+
34
40
  describe "#get_module_buffer" do
35
41
  before do
36
42
  allow(http_client).to receive(:get).
@@ -47,7 +53,7 @@ module PuppetLibrary::Forge
47
53
 
48
54
  buffer = forge.get_module_buffer("puppetlabs", "apache", "1.0.0")
49
55
 
50
- downloaded_file = File.join(cache_dir, "puppetlabs-apache-1.0.0.tar.gz")
56
+ downloaded_file = File.join(cache_dir.path, "puppetlabs-apache-1.0.0.tar.gz")
51
57
  expect(File.read downloaded_file).to eq "apache module"
52
58
  expect(buffer.read).to eq "apache module"
53
59
  end
@@ -55,7 +61,7 @@ module PuppetLibrary::Forge
55
61
 
56
62
  context "the second time it's called" do
57
63
  it "serves the cached module from the disk" do
58
- cached_module = File.join(cache_dir, "puppetlabs-apache-1.0.0.tar.gz")
64
+ cached_module = File.join(cache_dir.path, "puppetlabs-apache-1.0.0.tar.gz")
59
65
  File.open(cached_module, "w") do |file|
60
66
  file.write "apache module"
61
67
  end
@@ -20,43 +20,56 @@ module PuppetLibrary::Forge
20
20
  describe Directory do
21
21
  include ModuleSpecHelper
22
22
 
23
- let(:module_dir) { Tempdir.create("module_dir") }
24
- let(:module_repo) { Directory.new(module_dir) }
23
+ let(:module_dir) { Tempdir.new("module_dir") }
24
+ let(:forge) { Directory.new(module_dir) }
25
25
 
26
- after do
27
- rm_rf module_dir
28
- end
26
+ describe "#configure" do
27
+ it "exposes a configuration API" do
28
+ forge = Directory.configure do
29
+ path "."
30
+ end
31
+ expect(forge.instance_eval "@module_dir.path").to eq Dir.pwd
32
+ end
29
33
 
30
- describe "#initialize" do
31
34
  context "when the module directory doesn't exist" do
32
35
  before do
33
- rm_rf module_dir
36
+ rm_rf module_dir.path
34
37
  end
35
38
 
36
39
  it "raises an error" do
37
40
  expect {
38
- Directory.new(module_dir)
39
- }.to raise_error /Module directory .* doesn't exist/
41
+ Directory.configure do
42
+ path module_dir.path
43
+ end
44
+ }.to raise_error /No such file/
40
45
  end
41
46
  end
42
47
 
43
48
  context "when the module directory isn't readable" do
44
49
  before do
45
- chmod 0400, module_dir
50
+ chmod 0400, module_dir.path
46
51
  end
47
52
 
48
53
  after do
49
- chmod 0777, module_dir
54
+ chmod 0777, module_dir.path
50
55
  end
51
56
 
52
57
  it "raises an error" do
53
58
  expect {
54
- Directory.new(module_dir)
59
+ Directory.configure do
60
+ path module_dir.path
61
+ end
55
62
  }.to raise_error /Module directory .* isn't readable/
56
63
  end
57
64
  end
58
65
  end
59
66
 
67
+ describe "#prime" do
68
+ it "does nothing" do
69
+ forge.prime
70
+ end
71
+ end
72
+
60
73
  describe "#get_module" do
61
74
  context "when the module archive exists" do
62
75
  before do
@@ -64,7 +77,7 @@ module PuppetLibrary::Forge
64
77
  end
65
78
 
66
79
  it "returns a the module archive as a file buffer" do
67
- buffer = module_repo.get_module("puppetlabs", "apache", "1.0.0")
80
+ buffer = forge.get_module("puppetlabs", "apache", "1.0.0")
68
81
 
69
82
  expect(buffer.path).to end_with("puppetlabs-apache-1.0.0.tar.gz")
70
83
  end
@@ -72,7 +85,7 @@ module PuppetLibrary::Forge
72
85
 
73
86
  context "when the module file doesn't exist" do
74
87
  it "returns nil" do
75
- buffer = module_repo.get_module("puppetlabs", "noneixstant", "1.0.0")
88
+ buffer = forge.get_module("puppetlabs", "noneixstant", "1.0.0")
76
89
 
77
90
  expect(buffer).to be_nil
78
91
  end
@@ -87,7 +100,7 @@ module PuppetLibrary::Forge
87
100
  end
88
101
 
89
102
  it "returns a the module archive as a file buffer" do
90
- metadata = module_repo.get_all_metadata
103
+ metadata = forge.get_all_metadata
91
104
 
92
105
  v1 = metadata.find {|m| m["version"] == "1.0.0" }
93
106
  v2 = metadata.find {|m| m["version"] == "2.0.0" }
@@ -98,7 +111,7 @@ module PuppetLibrary::Forge
98
111
 
99
112
  context "when no modules exist" do
100
113
  it "returns an empty array" do
101
- result = module_repo.get_all_metadata
114
+ result = forge.get_all_metadata
102
115
 
103
116
  expect(result).to be_empty
104
117
  end
@@ -108,7 +121,7 @@ module PuppetLibrary::Forge
108
121
  describe "#get_metadata" do
109
122
  context "when the module directory is empty" do
110
123
  it "returns an empty array" do
111
- metadata_list = module_repo.get_metadata("puppetlabs", "apache")
124
+ metadata_list = forge.get_metadata("puppetlabs", "apache")
112
125
  expect(metadata_list).to be_empty
113
126
  end
114
127
  end
@@ -120,7 +133,7 @@ module PuppetLibrary::Forge
120
133
  end
121
134
 
122
135
  it "returns an array containing the module's versions' metadata" do
123
- metadata_list = module_repo.get_metadata("puppetlabs", "apache")
136
+ metadata_list = forge.get_metadata("puppetlabs", "apache")
124
137
  expect(metadata_list.size).to eq 2
125
138
  metadata_list = metadata_list.sort_by {|m| m["version"] }
126
139
  expect(metadata_list[0]["name"]).to eq "puppetlabs-apache"