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.
- checksums.yaml +4 -4
- data/CHANGELOG.yml +11 -0
- data/README.md +16 -7
- data/Rakefile +21 -21
- data/TODO.yml +10 -6
- data/bin/puppet-library +0 -1
- data/config.ru +14 -16
- data/features/step_definitions/sinatra_steps.rb +3 -12
- data/lib/puppet_library/forge.rb +1 -0
- data/lib/puppet_library/forge/abstract.rb +2 -1
- data/lib/puppet_library/forge/cache.rb +11 -7
- data/lib/puppet_library/forge/directory.rb +15 -13
- data/lib/puppet_library/forge/forge.rb +25 -0
- data/lib/puppet_library/forge/git_repository.rb +42 -17
- data/lib/puppet_library/forge/multi.rb +11 -1
- data/lib/puppet_library/forge/proxy.rb +14 -9
- data/lib/puppet_library/forge/source.rb +12 -13
- data/lib/puppet_library/http/cache/disk.rb +26 -8
- data/lib/puppet_library/http/cache/in_memory.rb +13 -10
- data/lib/puppet_library/http/cache/noop.rb +4 -1
- data/lib/puppet_library/puppet_library.rb +10 -7
- data/lib/puppet_library/puppet_module/modulefile.rb +5 -1
- data/lib/puppet_library/server.rb +13 -9
- data/lib/puppet_library/util.rb +1 -0
- data/lib/puppet_library/util/config_api.rb +115 -0
- data/lib/puppet_library/util/git.rb +36 -8
- data/lib/puppet_library/util/logging.rb +49 -0
- data/lib/puppet_library/util/patches.rb +21 -0
- data/lib/puppet_library/util/temp_dir.rb +20 -5
- data/lib/puppet_library/version.rb +1 -1
- data/puppet-library.gemspec +2 -0
- data/spec/archive/archive_reader_spec.rb +2 -6
- data/spec/archive/archiver_spec.rb +5 -9
- data/spec/forge/cache_spec.rb +13 -7
- data/spec/forge/directory_spec.rb +31 -18
- data/spec/forge/git_repository_spec.rb +60 -13
- data/spec/forge/multi_spec.rb +16 -0
- data/spec/forge/proxy_spec.rb +18 -0
- data/spec/forge/source_spec.rb +14 -9
- data/spec/http/cache/disk_spec.rb +11 -6
- data/spec/http/cache/in_memory_spec.rb +12 -0
- data/spec/http/cache/noop_spec.rb +6 -0
- data/spec/integration_test_helper.rb +3 -3
- data/spec/module_spec_helper.rb +2 -2
- data/spec/puppet_library_spec.rb +34 -16
- data/spec/puppet_module/modulefile_spec.rb +48 -9
- data/spec/server_spec.rb +28 -1
- data/spec/spec_helper.rb +2 -14
- data/spec/util/config_api_spec.rb +77 -0
- data/spec/util/git_spec.rb +20 -20
- data/spec/util/patches_spec.rb +18 -0
- data/test/directory_forge_integration_test.rb +6 -8
- data/test/offline_git_repo_forge_integration_test.rb +9 -14
- data/test/offline_proxy_forge_integration_test.rb +11 -14
- data/test/online_git_repo_forge_integration_test.rb +7 -8
- data/test/online_proxy_forge_integration_test.rb +10 -13
- data/test/source_forge_integration_test.rb +7 -8
- 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,
|
29
|
+
def initialize(source, cache_dir, cache_ttl_seconds = DEFAULT_CACHE_TTL_SECONDS)
|
26
30
|
@source = source
|
27
|
-
@
|
31
|
+
@cache_dir = cache_dir
|
28
32
|
@cache_ttl_seconds = cache_ttl_seconds
|
29
|
-
@git_dir = File.join(@
|
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
|
-
|
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
|
-
|
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 = @
|
98
|
-
|
99
|
-
|
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
|
-
|
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
|
-
|
37
|
-
@
|
38
|
-
|
39
|
-
|
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
|
data/puppet-library.gemspec
CHANGED
@@ -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.
|
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.
|
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
|
data/spec/forge/cache_spec.rb
CHANGED
@@ -19,18 +19,24 @@ require 'spec_helper'
|
|
19
19
|
|
20
20
|
module PuppetLibrary::Forge
|
21
21
|
describe Cache do
|
22
|
-
let(:cache_dir) { Tempdir.
|
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.
|
24
|
-
let(:
|
23
|
+
let(:module_dir) { Tempdir.new("module_dir") }
|
24
|
+
let(:forge) { Directory.new(module_dir) }
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
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.
|
39
|
-
|
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.
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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"
|