puppet-library 0.9.1 → 0.10.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 (37) hide show
  1. checksums.yaml +7 -7
  2. data/CHANGELOG.yml +1 -0
  3. data/README.md +9 -4
  4. data/Rakefile +44 -23
  5. data/TODO.yml +3 -4
  6. data/config.ru +28 -3
  7. data/lib/puppet_library/forge/cache.rb +19 -0
  8. data/lib/puppet_library/forge/directory.rb +16 -0
  9. data/lib/puppet_library/forge/git_repository.rb +57 -49
  10. data/lib/puppet_library/forge/proxy.rb +18 -4
  11. data/lib/puppet_library/forge/source.rb +10 -0
  12. data/lib/puppet_library/puppet_library.rb +1 -1
  13. data/lib/puppet_library/server.rb +12 -3
  14. data/lib/puppet_library/util/git.rb +103 -0
  15. data/lib/puppet_library/util/patches.rb +104 -0
  16. data/lib/puppet_library/util/temp_dir.rb +42 -0
  17. data/lib/puppet_library/util.rb +4 -70
  18. data/lib/puppet_library/version.rb +1 -1
  19. data/spec/archive/archive_reader_spec.rb +9 -2
  20. data/spec/archive/archiver_spec.rb +4 -0
  21. data/spec/forge/cache_spec.rb +4 -0
  22. data/spec/forge/directory_spec.rb +4 -0
  23. data/spec/forge/git_repository_spec.rb +5 -2
  24. data/spec/forge/source_spec.rb +4 -0
  25. data/spec/integration_test_helper.rb +42 -0
  26. data/spec/util/git_spec.rb +143 -0
  27. data/spec/util/patches_spec.rb +86 -0
  28. data/spec/util/temp_dir_spec.rb +35 -0
  29. data/test/directory_forge_integration_test.rb +96 -0
  30. data/test/offline_git_repo_forge_integration_test.rb +122 -0
  31. data/test/offline_proxy_forge_integration_test.rb +126 -0
  32. data/test/online_git_repo_forge_integration_test.rb +89 -0
  33. data/test/online_proxy_forge_integration_test.rb +93 -0
  34. data/test/source_forge_integration_test.rb +96 -0
  35. metadata +292 -118
  36. data/spec/util_spec.rb +0 -43
  37. data/test/librarian_puppet_integration_test.rb +0 -349
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 280994b916da7d8f05ba4cf98828e6459d6fdea4
4
- data.tar.gz: d1654492cdb5e30855c62b5fbabf08d7c1cb38a5
5
- SHA512:
6
- metadata.gz: d518cbe064ed9c664fd2198d070ce7db2576c761d9526a52c3ee577d8f067c0183462027dd78420810f82c1262f8fa8d9ac5e39c64b93e6a70e19baa8aff4022
7
- data.tar.gz: 28e347c2c9ed7215a6c2f2915264e463580d337e596464a6d5afddcb64d35bfec27b6a9be176712cb939f455f10b4694eea55adca0e98a90cb9d5f7337c953cc
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e4ad4f98c15d6ba4b89830bb6f30c72dc2ce3efd
4
+ data.tar.gz: 487e711b4ecdea363118803048f8320a902ed6e2
5
+ SHA512:
6
+ metadata.gz: 11bb00e50d4037bb7e14c60e69fe8c5d99e5f032dd4cb76adaa670462df40c62b7fe230488b2747fa730c685b88315560bb9543dff3698ef81894e4262ace257
7
+ data.tar.gz: 986c55e4faa32246bc1c9387180fec9488b2c153caed62038328f10a5af4b78180880f007e548e6fe0f48bd8e597b04c89a5d48eb3753c754c08855ae04eddc4
data/CHANGELOG.yml CHANGED
@@ -62,4 +62,5 @@
62
62
  - Fixed source forge bug that generated metadata incorrectly
63
63
  - tag: v0.10.0
64
64
  changes:
65
+ - Added new Git repo forge that serves modules from Git repositories, using tags for version numbers!
65
66
  - Fixed imports to enable easier embedding of Puppet Library
data/README.md CHANGED
@@ -146,11 +146,16 @@ require "rubygems"
146
146
  require "puppet_library"
147
147
 
148
148
  # NB: this config API is not yet stable, and may change without notice
149
- server = PuppetLibrary::Server.set_up do |library|
149
+ server = PuppetLibrary::Server.configure do |library|
150
150
  # Serve our private modules
151
- library.forge PuppetLibrary::Forge::Directory.new("/var/lib/modules")
152
- # Download all other moduls from the Puppet Forge
153
- library.forge PuppetLibrary::Forge::Proxy.new("http://forge.puppetlabs.com")
151
+ library.forge PuppetLibrary::Forge::Directory do |forge|
152
+ forge.path = "/var/lib/modules"
153
+ end
154
+
155
+ # Download all other modules from the Puppet Forge
156
+ library.forge PuppetLibrary::Forge::Proxy do |forge|
157
+ forge.url = "http://forge.puppetlabs.com"
158
+ end
154
159
  end
155
160
 
156
161
  run server
data/Rakefile CHANGED
@@ -17,7 +17,6 @@
17
17
 
18
18
  require 'bundler/gem_tasks'
19
19
  require 'rspec/core/rake_task'
20
- require 'coveralls/rake/task'
21
20
  require 'json'
22
21
  require 'yaml'
23
22
  require 'net/http'
@@ -61,7 +60,16 @@ rescue
61
60
  return true
62
61
  end
63
62
 
64
- Coveralls::RakeTask.new
63
+ if RUBY_VERSION.start_with? "1.8"
64
+ namespace :coveralls do
65
+ task :push do
66
+ puts "Skipping Coverage pushing because this Ruby version doesn't support it"
67
+ end
68
+ end
69
+ else
70
+ require 'coveralls/rake/task'
71
+ Coveralls::RakeTask.new
72
+ end
65
73
 
66
74
  desc "Run the specs"
67
75
  RSpec::Core::RakeTask.new(:spec)
@@ -102,7 +110,7 @@ end
102
110
  task :default => [:test, 'coveralls:push']
103
111
 
104
112
  desc "Check it works on all local rubies"
105
- task :verify => 'test-imports' do
113
+ task :verify => [ 'check-license', 'test-imports' ] do
106
114
  versions = SUPPORTED_RUBY_VERSIONS
107
115
  puts "\nRunning Specs".green
108
116
  spec_results = versions.map do |ruby_version|
@@ -122,13 +130,18 @@ task :verify => 'test-imports' do
122
130
  system "rvm #{ruby_version} do bundle exec rake features"
123
131
  end
124
132
 
133
+ gem_versions = versions.map do |ruby_version|
134
+ `rvm #{ruby_version} do gem --version`.strip
135
+ end
136
+
125
137
  puts "\nResults:\n".green
126
- results = [ spec_results, integration_test_results, acceptance_test_results ].transpose
127
- puts "+---------+-------+-------+-------+"
128
- puts "| Version | Specs | ITs | ATs |"
129
- puts "+---------+-------+-------+-------+"
130
- versions.zip(results).each do |(version, (spec_result, integration_test_result, acceptance_test_result))|
138
+ results = [ gem_versions, spec_results, integration_test_results, acceptance_test_results ].transpose
139
+ puts "+---------+----------+-------+-------+-------+"
140
+ puts "| Version | Gem Ver. | Specs | ITs | ATs |"
141
+ puts "+---------+----------+-------+-------+-------+"
142
+ versions.zip(results).each do |(version, (gem_version, spec_result, integration_test_result, acceptance_test_result))|
131
143
  v = version.ljust(7)
144
+ g = gem_version.ljust(8)
132
145
  s = spec_result ? "pass".green : "fail".red
133
146
  if ruby_version_supports_integration_test? version
134
147
  i = integration_test_result ? "pass".green : "fail".red
@@ -141,35 +154,44 @@ task :verify => 'test-imports' do
141
154
  else
142
155
  a = "skip".yellow
143
156
  end
144
- puts "| #{v} | #{s} | #{i} | #{a} |"
157
+ puts "| #{v} | #{g} | #{s} | #{i} | #{a} |"
145
158
  end
146
- puts "+---------+-------+-------+-------+"
159
+ puts "+---------+----------+-------+-------+-------+"
147
160
 
148
- versions.zip(results).each do |(version, (spec_result, integration_test_result))|
161
+ versions.zip(results).each do |(version, (gem_version, spec_result, integration_test_result, acceptance_test_result))|
149
162
  unless spec_result
150
163
  fail "Specs failed with Ruby #{version}"
151
164
  end
152
165
 
153
- if ruby_version_supports_integration_test?(version)
154
- unless integration_test_result
155
- fail "Integration tests failed with Ruby #{version}"
156
- end
166
+ unless integration_test_result
167
+ fail "Integration tests failed with Ruby #{version}"
168
+ end
169
+
170
+ unless acceptance_test_result
171
+ fail "Acceptance tests failed with Ruby #{version}"
157
172
  end
158
173
  end
159
174
  end
160
175
 
176
+ desc "Run simple checks"
177
+ task :check => [ "check-license", "test-imports" ]do
178
+ end
179
+
161
180
  desc "Check all files for license headers"
162
181
  task "check-license" do
163
- puts "Checking that all program files contain license headers"
182
+ print "Checking that all program files contain license headers"
164
183
 
165
184
  files = `git ls-files`.split "\n"
166
185
  ignored_files = File.read(".licenseignore").split("\n") << ".licenseignore"
167
186
  offending_files = files.reject { |file| File.read(file).include? "WITHOUT ANY WARRANTY" } - ignored_files
168
- if offending_files.empty?
169
- puts "Done"
187
+ ok = offending_files.empty?
188
+ result = if ok
189
+ "OK".green
170
190
  else
171
- abort("ERROR: THE FOLLOWING FILES HAVE NO LICENSE HEADERS: \n" + offending_files.join("\n"))
191
+ "FAIL".red
172
192
  end
193
+ puts " [ #{result} ]"
194
+ abort("ERROR: THE FOLLOWING FILES HAVE NO LICENSE HEADERS: \n" + offending_files.join("\n")) unless ok
173
195
  end
174
196
 
175
197
  desc "Print the version number"
@@ -200,8 +222,7 @@ end
200
222
 
201
223
  desc "Import files individually to make sure they can be imported externally"
202
224
  task "test-imports" do
203
- puts "Testing imports"
204
- puts
225
+ puts "Testing imports:"
205
226
  Dir.chdir "lib"
206
227
 
207
228
  paths = Dir["**/*.rb"].map {|f| f.sub /\.rb$/, "" }
@@ -209,7 +230,7 @@ task "test-imports" do
209
230
  errors = []
210
231
  paths.each do |path|
211
232
  print "importing #{path}..."
212
- output = `ruby -e '$LOAD_PATH.unshift(File.expand_path(".")); require "#{path}"' 2>&1`
233
+ output = `bundle exec ruby -e '$LOAD_PATH.unshift(File.expand_path(".")); require "#{path}"' 2>&1`
213
234
  print " ["
214
235
  if $?.success?
215
236
  print "OK".green
@@ -243,7 +264,7 @@ def upload_release_notes(version)
243
264
  end
244
265
 
245
266
  tag = "v#{version}"
246
- changelog = YAML.load_file("CHANGELOG.yml")
267
+ changelog = YAML.load_file(File.expand_path("CHANGELOG.yml", File.dirname(__FILE__)))
247
268
  release_notes = changelog.find {|release| release["tag"] == tag}
248
269
  changes = release_notes ? release_notes["changes"] : []
249
270
  description = changes.map { |change| "- #{change}" }.join("\n")
data/TODO.yml CHANGED
@@ -2,9 +2,6 @@ features:
2
2
  - Web UI:
3
3
  - asynchronous (index page loads too slowly)
4
4
  - Proxy a git repository:
5
- - make it threadsafe (checkouts into temp dirs)
6
- - make the specs fast
7
- - add an integration test
8
5
  - make it work with remote forges (clone and fetch on query/download)
9
6
  - make it fast (pre-clone repos on startup (maybe just warn if they can't be found). Maybe cache artifacts?)
10
7
  - logging
@@ -15,7 +12,9 @@ features:
15
12
  - clear proxy cache (web form and API)
16
13
  - delete modules from disk (web form)
17
14
  - Authentication
18
- - Make imports work properly from pry, and other projects
15
+ - Config APIs:
16
+ - parameterless blocks (especially for Server. Include PuppetLibrary::Forge aliased to Forge in scope)
17
+ - validation of required params
19
18
 
20
19
  dubious_features:
21
20
  - Proxy modules' source in a directory (supported individually for now: should we just leave it that way?)
data/config.ru CHANGED
@@ -18,9 +18,34 @@
18
18
  require 'rubygems'
19
19
  require 'puppet_library'
20
20
 
21
- server = PuppetLibrary::Server.set_up do |library|
22
- library.forge PuppetLibrary::Forge::Proxy.new("http://forge.puppetlabs.com")
23
- library.forge PuppetLibrary::Forge::Directory.new("/var/lib/modules")
21
+ server = PuppetLibrary::Server.configure do |library|
22
+ Forge = PuppetLibrary::Forge
23
+
24
+ # My custom modules
25
+ library.forge Forge::Directory do |forge|
26
+ forge.path = "/var/lib/modules"
27
+ end
28
+
29
+ # Unreleased versions from Github
30
+ library.forge Forge::GitRepository do |forge|
31
+ forge.repository = "https://github.com/puppetlabs/puppetlabs-apache.git"
32
+ forge.tag_regex = /[0-9.]+/
33
+ end
34
+
35
+ library.forge Forge::GitRepository do |forge|
36
+ forge.repository = "https://github.com/puppetlabs/puppetlabs-concat.git"
37
+ forge.tag_regex = /[0-9.]+/
38
+ end
39
+
40
+ library.forge Forge::GitRepository do |forge|
41
+ forge.repository = "https://github.com/puppetlabs/puppetlabs-stdlib.git"
42
+ forge.tag_regex = /[0-9.]+/
43
+ end
44
+
45
+ # Everything from The Forge
46
+ library.forge Forge::Proxy do |forge|
47
+ forge.url = "http://forge.puppetlabs.com"
48
+ end
24
49
  end
25
50
 
26
51
  run server
@@ -21,7 +21,26 @@ module PuppetLibrary::Forge
21
21
 
22
22
  # A forge that proxies a remote forge. All module archives downloaded from the
23
23
  # remote forged are cached to disk.
24
+ #
25
+ # <b>Usage:</b>
26
+ #
27
+ # forge = PuppetLibrary::Forge::Cache.configure do |repo|
28
+ # # The URL of the remote forge
29
+ # repo.url = "http://forge.example.com
30
+ #
31
+ # # The path to cache the files to on disk
32
+ # repo.path = "/var/modules/cache
33
+ # end
24
34
  class Cache < Proxy
35
+ class Config
36
+ attr_accessor :url, :path
37
+ end
38
+
39
+ def self.configure
40
+ config = Config.new
41
+ yield(config)
42
+ Cache.new(config.url, config.path)
43
+ end
25
44
 
26
45
  # * <tt>:url</tt> - The URL of the remote forge.
27
46
  # * <tt>:cache_dir</tt> - The directory in which to cache the downloaded artifacts.
@@ -27,7 +27,23 @@ module PuppetLibrary::Forge
27
27
  # * The modules must be named in the format <tt>author-modulename-version.tar.gz</tt>
28
28
  # * The modules must contain a +metadata.json+ file
29
29
  # That is, the format must be the same as what is produced by <tt>puppet module build</tt>
30
+ #
31
+ # <b>Usage:</b>
32
+ #
33
+ # forge = PuppetLibrary::Forge::Directory.configure do |repo|
34
+ # # The path to serve the modules from
35
+ # repo.path = "/var/modules/cache
36
+ # end
30
37
  class Directory < PuppetLibrary::Forge::Abstract
38
+ class Config
39
+ attr_accessor :path
40
+ end
41
+
42
+ def self.configure
43
+ config = Config.new
44
+ yield(config)
45
+ Directory.new(config.path)
46
+ end
31
47
 
32
48
  # * <tt>:module_dir</tt> - The directory containing the packaged modules.
33
49
  def initialize(module_dir)
@@ -15,92 +15,100 @@
15
15
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
16
 
17
17
  require 'json'
18
- require 'rubygems/package'
19
18
  require 'zlib'
19
+ require 'open3'
20
+ require 'rubygems/package'
20
21
  require 'puppet_library/forge/abstract'
22
+ require 'puppet_library/util/git'
23
+ require 'puppet_library/util/temp_dir'
21
24
 
22
25
  module PuppetLibrary::Forge
26
+ # A forge for serving modules from a Git repository
27
+ #
28
+ # <b>Usage:</b>
29
+ #
30
+ # forge = PuppetLibrary::Forge::GitRepository.configure do |repo|
31
+ # # The location of the git repository
32
+ # repo.source = "http://example.com/mymodule.git
33
+ #
34
+ # # A regular expression describing which tags to serve
35
+ # repo.include_tags = /[0-9.]+/
36
+ # end
23
37
  class GitRepository < PuppetLibrary::Forge::Abstract
24
- def initialize(author, name, version_tag_regex, git_path)
38
+ class Config
39
+ attr_accessor :source
40
+ attr_accessor :include_tags
41
+ end
42
+
43
+ def self.configure
44
+ config = Config.new
45
+ yield(config)
46
+ GitRepository.new(config.source, config.include_tags)
47
+ end
48
+
49
+ # * <tt>:source</tt> - The URL or path of the git repository
50
+ # * <tt>:version_tag_regex</tt> - A regex that describes which tags to serve
51
+ def initialize(source, version_tag_regex)
25
52
  super(self)
26
- @author = author
27
- @name = name
28
- @path = File.expand_path(git_path)
53
+ cache_path = PuppetLibrary::Util::TempDir.create("git-repo-cache")
29
54
  @version_tag_regex = version_tag_regex
55
+ @git = PuppetLibrary::Util::Git.new(source, cache_path)
56
+ end
57
+
58
+ def destroy!
59
+ @git.clear_cache!
30
60
  end
31
61
 
32
62
  def get_module(author, name, version)
33
- unless author == @author && name == @name
34
- return nil
35
- end
36
- unless tags.include? tag_name(version)
37
- return nil
38
- end
63
+ return nil unless tags.include? tag_for(version)
64
+
65
+ metadata = modulefile_for(version).to_metadata
66
+ return nil unless metadata["name"] == "#{author}-#{name}"
67
+
39
68
  on_tag_for(version) do
40
- PuppetLibrary::Archive::Archiver.archive_dir(@path, "#{@author}-#{@name}-#{version}") do |archive|
69
+ PuppetLibrary::Archive::Archiver.archive_dir('.', "#{metadata["name"]}-#{version}") do |archive|
41
70
  archive.add_file("metadata.json", 0644) do |entry|
42
- entry.write modulefile.to_metadata.to_json
71
+ entry.write metadata.to_json
43
72
  end
44
73
  end
45
74
  end
46
75
  end
47
76
 
48
- def get_metadata(author, module_name)
49
- unless author == @author && module_name == @name
50
- return []
51
- end
77
+ def get_all_metadata
52
78
  tags.map do |tag|
53
79
  modulefile_for_tag(tag).to_metadata
54
80
  end
55
81
  end
56
82
 
57
- def get_all_metadata
58
- get_metadata(@author, @name)
83
+ def get_metadata(author, module_name)
84
+ metadata = get_all_metadata
85
+ metadata.select do |m|
86
+ m["author"] == author
87
+ m["name"] == "#{author}-#{module_name}"
88
+ end
59
89
  end
60
90
 
61
91
  private
92
+
62
93
  def tags
63
- git("tag").split.select {|tag| tag =~ @version_tag_regex }
94
+ @git.tags.select {|tag| tag =~ @version_tag_regex }
64
95
  end
65
96
 
66
97
  def modulefile_for_tag(tag)
67
- modulefile_source = git("show refs/tags/#{tag}:Modulefile")
98
+ modulefile_source = @git.read_file("Modulefile", tag)
68
99
  PuppetLibrary::PuppetModule::Modulefile.parse(modulefile_source)
69
100
  end
70
101
 
71
- def modulefile
72
- modulefile_path = File.join(@path, "Modulefile")
73
- PuppetLibrary::PuppetModule::Modulefile.read(modulefile_path)
74
- end
75
-
76
- def package_name(version)
77
- "#{@author}-#{@name}-#{version}.tar.gz"
78
- end
79
-
80
- def tag_name(version)
81
- version
102
+ def modulefile_for(version)
103
+ modulefile_for_tag(tag_for(version))
82
104
  end
83
105
 
84
106
  def on_tag_for(version, &block)
85
- on_tag(tag_name(version), &block)
86
- end
87
-
88
- def on_tag(tag, &block)
89
- git "checkout #{tag}"
90
- in_dir(@path, &block)
107
+ @git.on_tag(tag_for(version), &block)
91
108
  end
92
109
 
93
- def in_dir(dir)
94
- origin = Dir.pwd
95
- Dir.chdir dir
96
- yield
97
- ensure
98
- Dir.chdir origin
99
- end
100
-
101
- def git(command)
102
- #TODO: redirection will fail on windows. How do we properly discard stderr?
103
- IO.popen("git --git-dir=#{@path}/.git --work-tree=#{@path} #{command} 2>/dev/null").read
110
+ def tag_for(version)
111
+ version
104
112
  end
105
113
  end
106
114
  end
@@ -22,13 +22,27 @@ require 'puppet_library/http/cache/noop'
22
22
  module PuppetLibrary::Forge
23
23
 
24
24
  # A forge that proxies a remote forge.
25
+ #
26
+ # <b>Usage:</b>
27
+ #
28
+ # forge = PuppetLibrary::Forge::Proxy.configure do |repo|
29
+ # # The URL of the remote forge
30
+ # repo.url = "http://forge.example.com
31
+ # end
25
32
  class Proxy
26
33
 
34
+ class Config
35
+ attr_accessor :url
36
+ end
37
+
38
+ def self.configure
39
+ config = Config.new
40
+ yield(config)
41
+ Proxy.new(config.url)
42
+ end
43
+
27
44
  # * <tt>:url</tt> - The URL of the remote forge.
28
- def initialize(url,
29
- query_cache = PuppetLibrary::Http::Cache::InMemory.new,
30
- download_cache = PuppetLibrary::Http::Cache::NoOp.new,
31
- http_client = PuppetLibrary::Http::HttpClient.new)
45
+ def initialize(url, query_cache = PuppetLibrary::Http::Cache::InMemory.new, download_cache = PuppetLibrary::Http::Cache::NoOp.new, http_client = PuppetLibrary::Http::HttpClient.new)
32
46
  @url = PuppetLibrary::Http::Url.normalize(url)
33
47
  @http_client = http_client
34
48
  @query_cache = query_cache
@@ -27,6 +27,16 @@ module PuppetLibrary::Forge
27
27
  # <b>Note:</b>
28
28
  # The module directory must have a +Modulefile+.
29
29
  class Source < PuppetLibrary::Forge::Abstract
30
+ class Config
31
+ attr_accessor :path
32
+ end
33
+
34
+ def self.configure
35
+ config = Config.new
36
+ yield(config)
37
+ Source.new(config.path)
38
+ end
39
+
30
40
  CACHE_TTL_MILLIS = 500
31
41
 
32
42
  # * <tt>:module_dir</tt> - The directory containing the module's source.
@@ -103,7 +103,7 @@ module PuppetLibrary
103
103
  load_defaults!(options)
104
104
  process_options!(options)
105
105
 
106
- Server.set_up do |server|
106
+ Server.configure do |server|
107
107
  options[:forges].each do |(forge_type, config)|
108
108
  subforge = forge_type.new(*config)
109
109
  server.forge subforge
@@ -25,7 +25,7 @@ module PuppetLibrary
25
25
  #
26
26
  # A Rack application that can be configured as follows:
27
27
  #
28
- # server = PuppetLibrary::Server.set_up do |library|
28
+ # server = PuppetLibrary::Server.configure do |library|
29
29
  # # Look for my modules locally
30
30
  # library.forge PuppetLibrary::Forge::Directory.new("/var/lib/modules")
31
31
  #
@@ -40,12 +40,21 @@ module PuppetLibrary
40
40
  @forge = forge
41
41
  end
42
42
 
43
- def forge(forge)
44
- @forge.add_forge forge
43
+ def forge(forge, &block)
44
+ if forge.is_a? Class
45
+ @forge.add_forge forge.configure(&block)
46
+ else
47
+ @forge.add_forge forge
48
+ end
45
49
  end
46
50
  end
47
51
 
48
52
  def self.set_up(&config_block)
53
+ puts "PuppetLibrary::Server::set_up deprecated: use #configure instead"
54
+ self.configure(&config_block)
55
+ end
56
+
57
+ def self.configure
49
58
  forge = Forge::Multi.new
50
59
  yield(Config.new(forge))
51
60
  Server.new(forge)
@@ -0,0 +1,103 @@
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 'fileutils'
18
+ require 'monitor'
19
+ require 'time'
20
+ require 'puppet_library/util/temp_dir'
21
+
22
+ module PuppetLibrary::Util
23
+ class Git
24
+ DEFAULT_CACHE_TTL_SECONDS = 60
25
+ def initialize(source, cache_path, cache_ttl_seconds = DEFAULT_CACHE_TTL_SECONDS)
26
+ @source = source
27
+ @cache_path = File.expand_path(cache_path)
28
+ @cache_ttl_seconds = cache_ttl_seconds
29
+ @git_dir = File.join(@cache_path, ".git")
30
+ @mutex = Monitor.new
31
+ end
32
+
33
+ def tags
34
+ update_cache!
35
+ git("tag").split
36
+ end
37
+
38
+ def on_tag(tag)
39
+ update_cache!
40
+ PuppetLibrary::Util::TempDir.use "git" do |path|
41
+ git "checkout #{tag}", path
42
+ yield
43
+ end
44
+ end
45
+
46
+ def read_file(path, tag)
47
+ update_cache!
48
+ git "show refs/tags/#{tag}:#{path}"
49
+ end
50
+
51
+ def clear_cache!
52
+ @mutex.synchronize do
53
+ FileUtils.rm_rf @cache_path
54
+ end
55
+ end
56
+
57
+ def update_cache!
58
+ create_cache unless cache_exists?
59
+ update_cache if cache_stale?
60
+ end
61
+
62
+ private
63
+ def create_cache
64
+ @mutex.synchronize do
65
+ git "clone --bare #{@source} #{@git_dir}" unless cache_exists?
66
+ FileUtils.touch fetch_file
67
+ end
68
+ end
69
+
70
+ def update_cache
71
+ @mutex.synchronize do
72
+ git "fetch --tags"
73
+ end
74
+ end
75
+
76
+ def cache_exists?
77
+ File.directory? @git_dir
78
+ end
79
+
80
+ def cache_stale?
81
+ Time.now - last_fetch > @cache_ttl_seconds
82
+ end
83
+
84
+ def last_fetch
85
+ if File.exist? fetch_file
86
+ File.stat(fetch_file).mtime
87
+ else
88
+ Time.at(0)
89
+ end
90
+ end
91
+
92
+ def fetch_file
93
+ File.join(@git_dir, "FETCH_HEAD")
94
+ end
95
+
96
+ 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
100
+ end
101
+ end
102
+ end
103
+ end