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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e4ad4f98c15d6ba4b89830bb6f30c72dc2ce3efd
4
- data.tar.gz: 487e711b4ecdea363118803048f8320a902ed6e2
3
+ metadata.gz: 5501e3e79913a9181ca6b829be328e8c6b3e3c64
4
+ data.tar.gz: 6625c303010b85e82a6f6d121379becb92634eff
5
5
  SHA512:
6
- metadata.gz: 11bb00e50d4037bb7e14c60e69fe8c5d99e5f032dd4cb76adaa670462df40c62b7fe230488b2747fa730c685b88315560bb9543dff3698ef81894e4262ace257
7
- data.tar.gz: 986c55e4faa32246bc1c9387180fec9488b2c153caed62038328f10a5af4b78180880f007e548e6fe0f48bd8e597b04c89a5d48eb3753c754c08855ae04eddc4
6
+ metadata.gz: 2cfa2f30bc16b177d5c272fa495b3d3b5f522959507faf17612b3234c2eb13fc19835b64d8703103692102e25a186188de8b977fd7764eb3c2083ab5e4ec0908
7
+ data.tar.gz: 4df43a457d93c2722154f295aeec9c43e250f4dba2ef7be9e881e2d56348c7adeafe88bd8c8186ee1cf171f844cb07865be2effb4a15258b1ecd1d55dc0e01a0
@@ -64,3 +64,14 @@
64
64
  changes:
65
65
  - Added new Git repo forge that serves modules from Git repositories, using tags for version numbers!
66
66
  - Fixed imports to enable easier embedding of Puppet Library
67
+ - tag: v0.11.0
68
+ changes:
69
+ - Added support for nontrivial tag names as version numbers when proxying Git repositories (e.g. tags named "v1.0.1")
70
+ - Added REST API to clear forge caches
71
+ - Git repositories are cached at startup for better performance and reliability
72
+ - Ensured temp directories are cleaned up more reliably
73
+ - Improved logging
74
+ - Improved Ruby config API for Rack/Passenger/embedded use
75
+ - Fixed issue with "Too many open files" caused by Git repo forges on Ruby 1.8
76
+ - Fixed issue Git repo forges with tags without Modulefiles
77
+ - Fixed issue Git repo forges with no description in Modulefile
data/README.md CHANGED
@@ -16,6 +16,7 @@ Plugins can be created to serve modules from arbitrary sources. Puppet Library c
16
16
  - proxying a remote forge (or forges)
17
17
  - caching proxied forges to disk
18
18
  - serving modules from source on disk
19
+ - serving modules from Git repositories using tags as version numbers!
19
20
 
20
21
  ## Installation
21
22
 
@@ -90,6 +91,7 @@ Puppet Library contains built-in support for:
90
91
  - serving packaged (`.tar.gz`) modules from a directory (or directories) of your choosing
91
92
  - proxying a remote forge (or forges)
92
93
  - serving modules from source on disk
94
+ - serving modules from Git repositories using tags as version numbers!
93
95
  - serving modules from a combination of the above
94
96
 
95
97
  ## Compatibility with other tools
@@ -145,16 +147,23 @@ cat > /webapps/puppet-library/config.ru <<EOF
145
147
  require "rubygems"
146
148
  require "puppet_library"
147
149
 
148
- # NB: this config API is not yet stable, and may change without notice
149
- server = PuppetLibrary::Server.configure do |library|
150
- # Serve our private modules
151
- library.forge PuppetLibrary::Forge::Directory do |forge|
152
- forge.path = "/var/lib/modules"
150
+ # NB: this config API is not yet stable, and may change without notice.
151
+ # The format shown is valid from Puppet Library v0.11.0
152
+ server = PuppetLibrary::Server.configure do
153
+ # Serve our private modules out of a directory on disk
154
+ forge :directory do
155
+ path = "/var/lib/modules"
156
+ end
157
+
158
+ # Serve the latest versions from GitHub
159
+ forge :git_repository do
160
+ source "http://github.com/example/puppetlabs-apache-fork.git"
161
+ include_tags /[0-9.]+/
153
162
  end
154
163
 
155
164
  # Download all other modules from the Puppet Forge
156
- library.forge PuppetLibrary::Forge::Proxy do |forge|
157
- forge.url = "http://forge.puppetlabs.com"
165
+ forge :proxy do
166
+ url "http://forge.puppetlabs.com"
158
167
  end
159
168
  end
160
169
 
data/Rakefile CHANGED
@@ -223,32 +223,32 @@ end
223
223
  desc "Import files individually to make sure they can be imported externally"
224
224
  task "test-imports" do
225
225
  puts "Testing imports:"
226
- Dir.chdir "lib"
227
-
228
- paths = Dir["**/*.rb"].map {|f| f.sub /\.rb$/, "" }
229
- paths = paths.sort_by {|p| p.count "/"}
230
- errors = []
231
- paths.each do |path|
232
- print "importing #{path}..."
233
- output = `bundle exec ruby -e '$LOAD_PATH.unshift(File.expand_path(".")); require "#{path}"' 2>&1`
234
- print " ["
235
- if $?.success?
236
- print "OK".green
237
- else
238
- print "FAIL".red
239
- errors << "#{path}: #{output.red}"
226
+ Dir.chdir "lib" do
227
+ paths = Dir["**/*.rb"].map {|f| f.sub /\.rb$/, "" }
228
+ paths = paths.sort_by {|p| p.count "/"}
229
+ errors = []
230
+ paths.each do |path|
231
+ print "importing #{path}..."
232
+ output = `bundle exec ruby -e '$LOAD_PATH.unshift(File.expand_path(".")); require "#{path}"' 2>&1`
233
+ print " ["
234
+ if $?.success?
235
+ print "OK".green
236
+ else
237
+ print "FAIL".red
238
+ errors << "#{path}: #{output.red}"
239
+ end
240
+ puts "]"
240
241
  end
241
- puts "]"
242
- end
243
242
 
244
- unless errors.empty?
245
- puts
246
- puts
247
- fail <<-EOFAILURE
243
+ unless errors.empty?
244
+ puts
245
+ puts
246
+ fail <<-EOFAILURE
248
247
  Failed to import some files:
249
248
 
250
249
  #{errors.join "\n\n"}
251
- EOFAILURE
250
+ EOFAILURE
251
+ end
252
252
  end
253
253
  end
254
254
 
data/TODO.yml CHANGED
@@ -1,10 +1,15 @@
1
1
  features:
2
2
  - Web UI:
3
3
  - asynchronous (index page loads too slowly)
4
- - Proxy a git repository:
5
- - make it work with remote forges (clone and fetch on query/download)
6
- - make it fast (pre-clone repos on startup (maybe just warn if they can't be found). Maybe cache artifacts?)
7
- - logging
4
+ - Git repo forge:
5
+ - make it more flexible:
6
+ - fail gracefully if we can't contact the remote repo
7
+ - Performance:
8
+ - cache stuff so it's faster
9
+ - logging:
10
+ - use Ruby logging
11
+ - include some verbose logging
12
+ - improve error messages (e.g. for when a module can't be untarred)
8
13
  - Named subforges:
9
14
  - per-subforge queries
10
15
  - upload modules (web form and API)
@@ -13,8 +18,7 @@ features:
13
18
  - delete modules from disk (web form)
14
19
  - Authentication
15
20
  - Config APIs:
16
- - parameterless blocks (especially for Server. Include PuppetLibrary::Forge aliased to Forge in scope)
17
- - validation of required params
21
+ - documentation
18
22
 
19
23
  dubious_features:
20
24
  - Proxy modules' source in a directory (supported individually for now: should we just leave it that way?)
@@ -19,7 +19,6 @@ lib_path = File.join(File.dirname(__FILE__), '..', 'lib')
19
19
  $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include? lib_path
20
20
 
21
21
  require "puppet_library"
22
- require 'optparse'
23
22
 
24
23
  module PuppetLibrary
25
24
  PuppetLibrary.new.go(ARGV)
data/config.ru CHANGED
@@ -18,33 +18,31 @@
18
18
  require 'rubygems'
19
19
  require 'puppet_library'
20
20
 
21
- server = PuppetLibrary::Server.configure do |library|
22
- Forge = PuppetLibrary::Forge
23
-
21
+ server = PuppetLibrary::Server.configure do
24
22
  # My custom modules
25
- library.forge Forge::Directory do |forge|
26
- forge.path = "/var/lib/modules"
23
+ forge :directory do
24
+ path "/var/puppet/modules"
27
25
  end
28
26
 
29
27
  # 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.]+/
28
+ forge :git_repository do
29
+ source "https://github.com/puppetlabs/puppetlabs-apache.git"
30
+ include_tags /[0-9.]+/
33
31
  end
34
32
 
35
- library.forge Forge::GitRepository do |forge|
36
- forge.repository = "https://github.com/puppetlabs/puppetlabs-concat.git"
37
- forge.tag_regex = /[0-9.]+/
33
+ forge :git_repository do
34
+ source "https://github.com/puppetlabs/puppetlabs-concat.git"
35
+ include_tags /[0-9.]+/
38
36
  end
39
37
 
40
- library.forge Forge::GitRepository do |forge|
41
- forge.repository = "https://github.com/puppetlabs/puppetlabs-stdlib.git"
42
- forge.tag_regex = /[0-9.]+/
38
+ forge :git_repository do
39
+ source "https://github.com/puppetlabs/puppetlabs-stdlib.git"
40
+ include_tags /[0-9.]+/
43
41
  end
44
42
 
45
43
  # Everything from The Forge
46
- library.forge Forge::Proxy do |forge|
47
- forge.url = "http://forge.puppetlabs.com"
44
+ forge :proxy do
45
+ url "http://forge.puppetlabs.com"
48
46
  end
49
47
  end
50
48
 
@@ -19,32 +19,23 @@ spec_path = File.expand_path("../../spec", File.dirname(__FILE__))
19
19
  $LOAD_PATH.unshift spec_path unless $LOAD_PATH.include? spec_path
20
20
 
21
21
  require 'module_spec_helper'
22
+ require 'spec_helper'
22
23
  require 'fileutils'
23
24
 
24
25
  include FileUtils
25
26
 
26
27
  def module_dir
27
- unless @module_dir
28
- file = Tempfile.new("module_dir")
29
- @module_dir = file.path
30
- file.delete
31
- end
32
- @module_dir
28
+ @module_dir ||= Tempdir.new("module_dir")
33
29
  end
34
30
 
35
31
  def module_writer
36
- @module_writer ||= ModuleSpecHelper::ModuleWriter.new(module_dir)
32
+ @module_writer ||= ModuleSpecHelper::ModuleWriter.new(module_dir.path)
37
33
  end
38
34
 
39
35
  Before do
40
- mkdir_p module_dir
41
36
  forge.add_forge PuppetLibrary::Forge::Directory.new(module_dir)
42
37
  end
43
38
 
44
- After do
45
- rm_rf module_dir
46
- end
47
-
48
39
  Given /^the "(.*?)" module is available at version "(.*?)"$/ do |full_name, version|
49
40
  author, name = full_name.split "/"
50
41
  module_writer.write_module(author, name, version)
@@ -22,6 +22,7 @@ module PuppetLibrary::Forge
22
22
  require 'puppet_library/forge/abstract'
23
23
  require 'puppet_library/forge/cache'
24
24
  require 'puppet_library/forge/directory'
25
+ require 'puppet_library/forge/forge'
25
26
  require 'puppet_library/forge/git_repository'
26
27
  require 'puppet_library/forge/multi'
27
28
  require 'puppet_library/forge/proxy'
@@ -15,6 +15,7 @@
15
15
  # You should have received a copy of the GNU General Public License
16
16
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
 
18
+ require 'puppet_library/forge/forge'
18
19
  require 'puppet_library/forge/search_result'
19
20
  require 'puppet_library/util'
20
21
 
@@ -24,7 +25,7 @@ module PuppetLibrary::Forge
24
25
  # types.
25
26
  #
26
27
  # See PuppetLibrary::Forge::Directory for an example
27
- class Abstract
28
+ class Abstract < Forge
28
29
  def initialize(module_repo)
29
30
  @repo = module_repo
30
31
  end
@@ -17,6 +17,8 @@
17
17
 
18
18
  require 'puppet_library/forge/proxy'
19
19
  require 'puppet_library/http/http_client'
20
+ require 'puppet_library/util/config_api'
21
+
20
22
  module PuppetLibrary::Forge
21
23
 
22
24
  # A forge that proxies a remote forge. All module archives downloaded from the
@@ -32,14 +34,16 @@ module PuppetLibrary::Forge
32
34
  # repo.path = "/var/modules/cache
33
35
  # end
34
36
  class Cache < Proxy
35
- class Config
36
- attr_accessor :url, :path
37
- end
38
37
 
39
- def self.configure
40
- config = Config.new
41
- yield(config)
42
- Cache.new(config.url, config.path)
38
+ def self.configure(&block)
39
+ config_api = PuppetLibrary::Util::ConfigApi.for(Cache) do
40
+ required :url, "URL"
41
+ required :path, "path" do |path|
42
+ Dir.new(path)
43
+ end
44
+ end
45
+ config = config_api.configure(&block)
46
+ Cache.new(config.get_url, config.get_path)
43
47
  end
44
48
 
45
49
  # * <tt>:url</tt> - The URL of the remote forge.
@@ -17,6 +17,7 @@
17
17
  require 'json'
18
18
  require 'puppet_library/forge/abstract'
19
19
  require 'puppet_library/archive/archive_reader'
20
+ require 'puppet_library/util/config_api'
20
21
 
21
22
  module PuppetLibrary::Forge
22
23
 
@@ -35,27 +36,28 @@ module PuppetLibrary::Forge
35
36
  # repo.path = "/var/modules/cache
36
37
  # end
37
38
  class Directory < PuppetLibrary::Forge::Abstract
38
- class Config
39
- attr_accessor :path
40
- end
41
39
 
42
- def self.configure
43
- config = Config.new
44
- yield(config)
45
- Directory.new(config.path)
40
+ def self.configure(&block)
41
+ config_api = PuppetLibrary::Util::ConfigApi.for(Directory) do
42
+ required :path, "path to a directory to serve modules from" do |dir|
43
+ Dir.new(File.expand_path(dir)).tap do |dir|
44
+ raise "Module directory '#{dir}' isn't readable" unless File.executable? dir
45
+ end
46
+ end
47
+ end
48
+ config = config_api.configure(&block)
49
+ Directory.new(config.get_path)
46
50
  end
47
51
 
48
52
  # * <tt>:module_dir</tt> - The directory containing the packaged modules.
49
53
  def initialize(module_dir)
50
54
  super(self)
51
- raise "Module directory '#{module_dir}' doesn't exist" unless File.directory? module_dir
52
- raise "Module directory '#{module_dir}' isn't readable" unless File.executable? module_dir
53
55
  @module_dir = module_dir
54
56
  end
55
57
 
56
58
  def get_module(author, name, version)
57
59
  file_name = "#{author}-#{name}-#{version}.tar.gz"
58
- path = File.join(File.expand_path(@module_dir), file_name)
60
+ path = File.join(File.expand_path(@module_dir.path), file_name)
59
61
  if File.exist? path
60
62
  File.open(path, 'r')
61
63
  else
@@ -63,8 +65,8 @@ module PuppetLibrary::Forge
63
65
  end
64
66
  end
65
67
 
66
- def get_metadata(author = "*", module_name = "")
67
- Dir["#{@module_dir}/#{author}-#{module_name}*"].map do |module_path|
68
+ def get_metadata(author, module_name)
69
+ Dir["#{@module_dir.path}/#{author}-#{module_name}*"].map do |module_path|
68
70
  archive = PuppetLibrary::Archive::ArchiveReader.new(module_path)
69
71
  metadata_file = archive.read_entry %r[[^/]+/metadata\.json$]
70
72
  JSON.parse(metadata_file)
@@ -72,7 +74,7 @@ module PuppetLibrary::Forge
72
74
  end
73
75
 
74
76
  def get_all_metadata
75
- get_metadata
77
+ get_metadata("*", "")
76
78
  end
77
79
  end
78
80
  end
@@ -0,0 +1,25 @@
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
+ module PuppetLibrary::Forge
18
+ class Forge
19
+ def prime
20
+ end
21
+
22
+ def clear_cache
23
+ end
24
+ end
25
+ end
@@ -21,6 +21,8 @@ require 'rubygems/package'
21
21
  require 'puppet_library/forge/abstract'
22
22
  require 'puppet_library/util/git'
23
23
  require 'puppet_library/util/temp_dir'
24
+ require 'puppet_library/util/config_api'
25
+ require 'puppet_library/http/cache/in_memory'
24
26
 
25
27
  module PuppetLibrary::Forge
26
28
  # A forge for serving modules from a Git repository
@@ -35,27 +37,38 @@ module PuppetLibrary::Forge
35
37
  # repo.include_tags = /[0-9.]+/
36
38
  # end
37
39
  class GitRepository < PuppetLibrary::Forge::Abstract
38
- class Config
39
- attr_accessor :source
40
- attr_accessor :include_tags
41
- end
42
40
 
43
- def self.configure
44
- config = Config.new
45
- yield(config)
46
- GitRepository.new(config.source, config.include_tags)
41
+ def self.configure(&block)
42
+ config_api = PuppetLibrary::Util::ConfigApi.for(GitRepository) do
43
+ required :source, "path or URL"
44
+ required :include_tags, "regex" do |value|
45
+ value.tap do |value|
46
+ raise "not a regex" unless value.is_a? Regexp
47
+ end
48
+ end
49
+ end
50
+
51
+ config = config_api.configure(&block)
52
+ cache_dir = PuppetLibrary::Util::TempDir.new("git-repo-cache")
53
+ git = PuppetLibrary::Util::Git.new(config.get_source, cache_dir)
54
+ GitRepository.new(git, config.get_include_tags)
47
55
  end
48
56
 
49
57
  # * <tt>:source</tt> - The URL or path of the git repository
50
58
  # * <tt>:version_tag_regex</tt> - A regex that describes which tags to serve
51
- def initialize(source, version_tag_regex)
59
+ def initialize(git, version_tag_regex)
52
60
  super(self)
53
- cache_path = PuppetLibrary::Util::TempDir.create("git-repo-cache")
54
61
  @version_tag_regex = version_tag_regex
55
- @git = PuppetLibrary::Util::Git.new(source, cache_path)
62
+ @git = git
63
+ @modulefile_cache = PuppetLibrary::Http::Cache::InMemory.new
64
+ @tags_cache = PuppetLibrary::Http::Cache::InMemory.new
65
+ end
66
+
67
+ def prime
68
+ @git.update_cache!
56
69
  end
57
70
 
58
- def destroy!
71
+ def clear_cache
59
72
  @git.clear_cache!
60
73
  end
61
74
 
@@ -89,14 +102,19 @@ module PuppetLibrary::Forge
89
102
  end
90
103
 
91
104
  private
92
-
93
105
  def tags
94
- @git.tags.select {|tag| tag =~ @version_tag_regex }
106
+ @tags_cache.get do
107
+ tags = @git.tags
108
+ tags = tags.select {|tag| tag =~ @version_tag_regex }
109
+ tags = tags.select {|tag| @git.file_exists?("Modulefile", tag) }
110
+ end
95
111
  end
96
112
 
97
113
  def modulefile_for_tag(tag)
98
- modulefile_source = @git.read_file("Modulefile", tag)
99
- PuppetLibrary::PuppetModule::Modulefile.parse(modulefile_source)
114
+ @modulefile_cache.get(tag) do
115
+ modulefile_source = @git.read_file("Modulefile", tag)
116
+ PuppetLibrary::PuppetModule::Modulefile.parse(modulefile_source)
117
+ end
100
118
  end
101
119
 
102
120
  def modulefile_for(version)
@@ -108,7 +126,14 @@ module PuppetLibrary::Forge
108
126
  end
109
127
 
110
128
  def tag_for(version)
111
- version
129
+ tag_versions[version]
130
+ end
131
+
132
+ def tag_versions
133
+ tags_to_versions = tags.map do |tag|
134
+ [ modulefile_for_tag(tag).get_version, tag ]
135
+ end
136
+ Hash[tags_to_versions]
112
137
  end
113
138
  end
114
139
  end