puppet-library 0.10.0 → 0.11.0

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 (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"