puppet-library 0.9.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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