rubycut-babushka 0.10.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +31 -0
  3. data/README.markdown +246 -0
  4. data/Rakefile +26 -0
  5. data/bin/babushka +11 -0
  6. data/deps/babushka.rb +101 -0
  7. data/deps/dev.rb +12 -0
  8. data/deps/fhs.rb +31 -0
  9. data/deps/git.rb +29 -0
  10. data/deps/homebrew.rb +30 -0
  11. data/deps/os_x.rb +33 -0
  12. data/deps/packages.rb +22 -0
  13. data/deps/pkg_managers.rb +110 -0
  14. data/deps/ruby.rb +23 -0
  15. data/deps/rubygems.rb +24 -0
  16. data/deps/system.rb +10 -0
  17. data/deps/templates/app.rb +68 -0
  18. data/deps/templates/external.rb +12 -0
  19. data/deps/templates/installer.rb +31 -0
  20. data/deps/templates/managed.rb +105 -0
  21. data/deps/templates/ppa.rb +24 -0
  22. data/deps/templates/src.rb +42 -0
  23. data/deps/templates/tmbundle.rb +15 -0
  24. data/lib/babushka.rb +28 -0
  25. data/lib/babushka/accepts_block_for.rb +72 -0
  26. data/lib/babushka/accepts_list_for.rb +49 -0
  27. data/lib/babushka/accepts_value_for.rb +24 -0
  28. data/lib/babushka/base.rb +78 -0
  29. data/lib/babushka/bug_reporter.rb +55 -0
  30. data/lib/babushka/cmdline.rb +133 -0
  31. data/lib/babushka/cmdline/handler.rb +41 -0
  32. data/lib/babushka/cmdline/helpers.rb +127 -0
  33. data/lib/babushka/cmdline/parser.rb +69 -0
  34. data/lib/babushka/colorizer.rb +59 -0
  35. data/lib/babushka/core_patches/array.rb +171 -0
  36. data/lib/babushka/core_patches/blank.rb +22 -0
  37. data/lib/babushka/core_patches/bytes.rb +52 -0
  38. data/lib/babushka/core_patches/hash.rb +107 -0
  39. data/lib/babushka/core_patches/hashish.rb +14 -0
  40. data/lib/babushka/core_patches/integer.rb +25 -0
  41. data/lib/babushka/core_patches/io.rb +8 -0
  42. data/lib/babushka/core_patches/numeric.rb +16 -0
  43. data/lib/babushka/core_patches/object.rb +27 -0
  44. data/lib/babushka/core_patches/string.rb +116 -0
  45. data/lib/babushka/core_patches/symbol.rb +12 -0
  46. data/lib/babushka/core_patches/try.rb +15 -0
  47. data/lib/babushka/core_patches/uri.rb +24 -0
  48. data/lib/babushka/dep.rb +470 -0
  49. data/lib/babushka/dep_context.rb +18 -0
  50. data/lib/babushka/dep_definer.rb +115 -0
  51. data/lib/babushka/dep_pool.rb +49 -0
  52. data/lib/babushka/dep_runner.rb +85 -0
  53. data/lib/babushka/dsl.rb +26 -0
  54. data/lib/babushka/git_repo.rb +185 -0
  55. data/lib/babushka/helpers/git_helpers.rb +32 -0
  56. data/lib/babushka/helpers/log_helpers.rb +176 -0
  57. data/lib/babushka/helpers/path_helpers.rb +34 -0
  58. data/lib/babushka/helpers/run_helpers.rb +145 -0
  59. data/lib/babushka/helpers/shell_helpers.rb +229 -0
  60. data/lib/babushka/helpers/suggest_helpers.rb +16 -0
  61. data/lib/babushka/helpers/uri_helpers.rb +36 -0
  62. data/lib/babushka/ip.rb +160 -0
  63. data/lib/babushka/lambda_chooser.rb +40 -0
  64. data/lib/babushka/levenshtein.rb +125 -0
  65. data/lib/babushka/meta_dep.rb +65 -0
  66. data/lib/babushka/meta_dep_context.rb +15 -0
  67. data/lib/babushka/parameter.rb +143 -0
  68. data/lib/babushka/pkg_helper.rb +81 -0
  69. data/lib/babushka/pkg_helpers/apt_helper.rb +61 -0
  70. data/lib/babushka/pkg_helpers/base_helper.rb +19 -0
  71. data/lib/babushka/pkg_helpers/binpkgsrc_helper.rb +48 -0
  72. data/lib/babushka/pkg_helpers/binports_helper.rb +34 -0
  73. data/lib/babushka/pkg_helpers/brew_helper.rb +110 -0
  74. data/lib/babushka/pkg_helpers/gem_helper.rb +120 -0
  75. data/lib/babushka/pkg_helpers/macports_helper.rb +22 -0
  76. data/lib/babushka/pkg_helpers/npm_helper.rb +45 -0
  77. data/lib/babushka/pkg_helpers/pacman_helper.rb +27 -0
  78. data/lib/babushka/pkg_helpers/pip_helper.rb +45 -0
  79. data/lib/babushka/pkg_helpers/src_helper.rb +16 -0
  80. data/lib/babushka/pkg_helpers/yum_helper.rb +25 -0
  81. data/lib/babushka/popen.rb +40 -0
  82. data/lib/babushka/prompt.rb +176 -0
  83. data/lib/babushka/renderable.rb +67 -0
  84. data/lib/babushka/resource.rb +215 -0
  85. data/lib/babushka/run_reporter.rb +60 -0
  86. data/lib/babushka/shell.rb +108 -0
  87. data/lib/babushka/source.rb +216 -0
  88. data/lib/babushka/source_pool.rb +146 -0
  89. data/lib/babushka/system_definitions.rb +97 -0
  90. data/lib/babushka/system_profile.rb +210 -0
  91. data/lib/babushka/task.rb +142 -0
  92. data/lib/babushka/vars.rb +108 -0
  93. data/lib/babushka/version_of.rb +65 -0
  94. data/lib/babushka/version_str.rb +57 -0
  95. data/lib/babushka/xml_string.rb +28 -0
  96. data/lib/components.rb +82 -0
  97. data/lib/fancypath/fancypath.rb +200 -0
  98. data/lib/inkan/inkan.rb +76 -0
  99. data/spec/acceptance/acceptance.rb +43 -0
  100. data/spec/acceptance_helper.rb +113 -0
  101. data/spec/archives/Blah.app.zip +0 -0
  102. data/spec/archives/archive.tar +0 -0
  103. data/spec/archives/archive.tar.bz2 +0 -0
  104. data/spec/archives/archive.tar.gz +0 -0
  105. data/spec/archives/archive.tbz2 +0 -0
  106. data/spec/archives/archive.tgz +0 -0
  107. data/spec/archives/archive.zip +0 -0
  108. data/spec/archives/content.txt +5 -0
  109. data/spec/archives/invalid_archive +5 -0
  110. data/spec/archives/nested archive/content.txt +5 -0
  111. data/spec/archives/nested_archive.tar +0 -0
  112. data/spec/archives/really_a_gzip.zip +0 -0
  113. data/spec/archives/test-0.3.1.tgz +0 -0
  114. data/spec/archives/tgz_archive +0 -0
  115. data/spec/archives/zip_without_extension +0 -0
  116. data/spec/babushka/accepts_for_spec.rb +174 -0
  117. data/spec/babushka/accepts_for_support.rb +72 -0
  118. data/spec/babushka/cmdline/console_spec.rb +11 -0
  119. data/spec/babushka/cmdline/help_spec.rb +61 -0
  120. data/spec/babushka/cmdline/version_spec.rb +10 -0
  121. data/spec/babushka/core_patches_spec.rb +171 -0
  122. data/spec/babushka/dep_context_spec.rb +58 -0
  123. data/spec/babushka/dep_definer_spec.rb +152 -0
  124. data/spec/babushka/dep_definer_support.rb +36 -0
  125. data/spec/babushka/dep_spec.rb +567 -0
  126. data/spec/babushka/dep_support.rb +29 -0
  127. data/spec/babushka/deps_spec.rb +113 -0
  128. data/spec/babushka/gem_helper_spec.rb +90 -0
  129. data/spec/babushka/git_repo_spec.rb +396 -0
  130. data/spec/babushka/ip_spec.rb +131 -0
  131. data/spec/babushka/lambda_chooser_spec.rb +115 -0
  132. data/spec/babushka/meta_dep_definer_spec.rb +127 -0
  133. data/spec/babushka/meta_dep_wrapper_spec.rb +32 -0
  134. data/spec/babushka/parameter_spec.rb +135 -0
  135. data/spec/babushka/path_helpers_spec.rb +102 -0
  136. data/spec/babushka/prompt_spec.rb +188 -0
  137. data/spec/babushka/renderable_spec.rb +100 -0
  138. data/spec/babushka/resource_spec.rb +141 -0
  139. data/spec/babushka/run_helpers_spec.rb +26 -0
  140. data/spec/babushka/shell_helpers_spec.rb +244 -0
  141. data/spec/babushka/shell_spec.rb +19 -0
  142. data/spec/babushka/source_pool_spec.rb +320 -0
  143. data/spec/babushka/source_pool_support.rb +31 -0
  144. data/spec/babushka/source_spec.rb +382 -0
  145. data/spec/babushka/source_support.rb +17 -0
  146. data/spec/babushka/system_profile_spec.rb +61 -0
  147. data/spec/babushka/task_spec.rb +141 -0
  148. data/spec/babushka/uri_spec.rb +13 -0
  149. data/spec/babushka/vars_spec.rb +59 -0
  150. data/spec/babushka/version_of_spec.rb +110 -0
  151. data/spec/babushka/version_str_spec.rb +130 -0
  152. data/spec/babushka/version_str_support.rb +37 -0
  153. data/spec/babushka/xml_string_spec.rb +98 -0
  154. data/spec/deps/bad/broken.rb +7 -0
  155. data/spec/deps/bad/working.rb +3 -0
  156. data/spec/deps/good/meta.rb +14 -0
  157. data/spec/deps/good/test.rb +11 -0
  158. data/spec/deps/outer/deps.rb +19 -0
  159. data/spec/deps/outer/more deps.rb +11 -0
  160. data/spec/deps/params/params.rb +10 -0
  161. data/spec/fancypath/fancypath_spec.rb +272 -0
  162. data/spec/fancypath_support.rb +10 -0
  163. data/spec/inkan/inkan_spec.rb +217 -0
  164. data/spec/renderable/different_example.conf.erb +4 -0
  165. data/spec/renderable/example.conf.erb +3 -0
  166. data/spec/renderable/example.sh +6 -0
  167. data/spec/renderable/with_binding.conf.erb +4 -0
  168. data/spec/renderable/xml_example.conf.erb +8 -0
  169. data/spec/repos/remote.git.tgz +0 -0
  170. data/spec/spec_helper.rb +87 -0
  171. metadata +238 -0
@@ -0,0 +1,216 @@
1
+ module Babushka
2
+ class SourceError < StandardError
3
+ end
4
+ class Source
5
+ include GitHelpers
6
+ include LogHelpers
7
+ extend LogHelpers
8
+ extend ShellHelpers
9
+ include PathHelpers
10
+ extend PathHelpers
11
+
12
+ attr_reader :name, :uri, :deps, :templates
13
+
14
+ def self.present
15
+ source_prefix.glob('*').map(&:p).select {|path|
16
+ path.directory?
17
+ }.map {|path|
18
+ Source.for_path path
19
+ }.select {|source|
20
+ source.present?
21
+ }
22
+ end
23
+
24
+ def self.for_path path
25
+ remote = cd(path) { shell "git config remote.origin.url" }
26
+ if remote.nil?
27
+ Source.new path # local source
28
+ else
29
+ Source.new remote, :name => path.basename # remote source with custom path
30
+ end
31
+ end
32
+
33
+ def self.for_remote name
34
+ Source.new(default_remote_for(name), :name => name)
35
+ end
36
+
37
+ def self.default_remote_for name
38
+ "git://github.com/#{name}/babushka-deps.git"
39
+ end
40
+
41
+ require 'uri'
42
+ def self.discover_uri_and_type path
43
+ if path.nil?
44
+ [nil, :implicit]
45
+ elsif path.to_s[/^(git|http|file):\/\//]
46
+ [path.to_s, :public]
47
+ elsif path.to_s[/^(\w+@)?[a-zA-Z0-9.\-]+:/]
48
+ [path.to_s, :private]
49
+ else
50
+ [path.p, :local]
51
+ end
52
+ end
53
+
54
+ def self.default_name_for_uri uri
55
+ if uri.nil?
56
+ nil
57
+ else
58
+ File.basename(uri.to_s).chomp('.git')
59
+ end
60
+ end
61
+
62
+ def initialize path, opts = {}
63
+ raise ArgumentError, "Source.new options must be passed as a hash, not as #{opts.inspect}." unless opts.is_a?(Hash)
64
+ @uri, @type = self.class.discover_uri_and_type(path)
65
+ @name = (opts[:name] || self.class.default_name_for_uri(@uri)).to_s
66
+ @deps = DepPool.new self
67
+ @templates = DepPool.new self
68
+ @loaded = @currently_loading = false
69
+ end
70
+
71
+ def uri_matches? path
72
+ self.class.discover_uri_and_type(path).first == uri
73
+ end
74
+
75
+ def find dep_spec
76
+ load!
77
+ deps.for(dep_spec)
78
+ end
79
+
80
+ def find_template template_spec
81
+ load!
82
+ templates.for(template_spec)
83
+ end
84
+
85
+ def prefix
86
+ self.class.source_prefix
87
+ end
88
+ def path
89
+ if implicit? || local?
90
+ @uri
91
+ else
92
+ prefix / name
93
+ end
94
+ end
95
+
96
+ def repo
97
+ @repo ||= GitRepo.new(path) if cloneable?
98
+ end
99
+
100
+ def updated_at
101
+ Time.now - File.mtime(path)
102
+ end
103
+ def description_pieces
104
+ [
105
+ name,
106
+ uri.to_s,
107
+ type,
108
+ ("#{updated_at.round.xsecs} ago" if cloneable?)
109
+ ]
110
+ end
111
+ def type
112
+ @type
113
+ end
114
+ def cloneable?
115
+ [:public, :private].include? type
116
+ end
117
+ def cloned?
118
+ File.directory? path / '.git'
119
+ end
120
+ def present?
121
+ cloneable? ? cloned? : path.exists?
122
+ end
123
+ def local?
124
+ type == :local
125
+ end
126
+ def implicit?
127
+ type == :implicit
128
+ end
129
+
130
+ def == other
131
+ [:name, :uri, :type].all? {|method_name| other.respond_to? method_name } &&
132
+ name == other.name &&
133
+ uri == other.uri &&
134
+ type == other.type
135
+ end
136
+
137
+ def add!
138
+ if !cloneable?
139
+ log "Nothing to add for #{name}."
140
+ else
141
+ raise_unless_addable!
142
+ log_block "Adding #{name} from #{uri}" do
143
+ update!
144
+ end
145
+ end
146
+ end
147
+
148
+ def load!
149
+ unless @currently_loading
150
+ @currently_loading = true
151
+ update! if cloneable?
152
+ load_deps! unless implicit? # implicit sources can't be loaded.
153
+ @currently_loading = false
154
+ end
155
+ end
156
+
157
+ def load_deps!
158
+ unless @loaded
159
+ path.p.glob('**/*.rb').each {|f|
160
+ Base.sources.load_context :source => self, :path => f do
161
+ begin
162
+ load f
163
+ rescue Exception => e
164
+ log_error "#{e.backtrace.first}: #{e.message}"
165
+ log "Check #{(e.backtrace.detect {|l| l[f] } || f).sub(/\:in [^:]+$/, '')}."
166
+ debug e.backtrace * "\n"
167
+ end
168
+ end
169
+ }
170
+ debug "Loaded #{deps.count} deps from #{path}." unless deps.count.zero?
171
+ @loaded = true
172
+ end
173
+ end
174
+
175
+ def update!
176
+ if @updated
177
+ debug "Already pulled #{name} (#{uri}) this session."
178
+ true
179
+ elsif @updated == false
180
+ debug "Not updating #{name} (#{uri}) - it's offline."
181
+ elsif Base.sources.local_only?
182
+ debug "Not pulling #{name} (#{uri}) - in local-only mode."
183
+ true
184
+ elsif repo.exists? && repo.dirty?
185
+ log "Not updating #{name} (#{path}) because there are local changes."
186
+ elsif repo.exists? && repo.ahead?
187
+ log "Not updating #{name} (#{path}) because it's ahead of origin."
188
+ else
189
+ git(uri, :to => path, :log => true).tap {|result|
190
+ log "Marking #{uri} as offline for this run." unless result
191
+ @updated = result || false
192
+ }
193
+ end
194
+ end
195
+
196
+ private
197
+
198
+ def raise_unless_addable!
199
+ present_sources = Base.sources.all_present
200
+ uri_dup_source = present_sources.detect {|s| s.uri == uri && s.name != name }
201
+ name_dup_source = present_sources.detect {|s| s.name == name && s.uri != uri }
202
+ raise SourceError, "There is already a source called '#{name_dup_source.name}' (it contains #{name_dup_source.uri})." unless name_dup_source.nil?
203
+ raise SourceError, "The source #{uri_dup_source.uri} is already present (as '#{uri_dup_source.name}')." unless uri_dup_source.nil?
204
+ end
205
+
206
+ def self.source_prefix
207
+ SourcePrefix.p
208
+ end
209
+
210
+ public
211
+
212
+ def inspect
213
+ "#<Source:#{object_id} '#{name}' (#{deps.count} dep#{'s' unless deps.count == 1})>"
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,146 @@
1
+ module Babushka
2
+ class SourcePool
3
+ include Singleton
4
+
5
+ include LogHelpers
6
+
7
+ SEPARATOR = ':'
8
+
9
+ def current
10
+ @_cached_current ||= default.concat(standard)
11
+ @_cached_current.dup
12
+ end
13
+
14
+ def default
15
+ [anonymous, core].dup
16
+ end
17
+
18
+ def current_names
19
+ current.map {|source| source.deps.names }.flatten.uniq
20
+ end
21
+
22
+ def all_present
23
+ current.concat(Source.present)
24
+ end
25
+
26
+ def anonymous
27
+ @_cached_anonymous ||= Source.new(nil, :name => 'anonymous')
28
+ end
29
+ def core
30
+ @_cached_core ||= Source.new(Path.path / 'deps', :name => 'core')
31
+ end
32
+ def current_dir
33
+ @_cached_current_dir ||= Source.new('./babushka-deps', :name => 'current dir')
34
+ end
35
+ def personal
36
+ @_cached_personal ||= Source.new('~/.babushka/deps', :name => 'personal')
37
+ end
38
+
39
+ def standard
40
+ [current_dir, personal]
41
+ end
42
+
43
+ def source_for name
44
+ all_present.detect {|source| source.name == name } || Source.for_remote(name)
45
+ end
46
+
47
+ def dep_for dep_spec, opts = {}
48
+ if dep_spec.is_a?(Dep)
49
+ dep_spec
50
+ elsif dep_spec[/#{SEPARATOR}/] # If a source was specified, that's where we load from.
51
+ source_name, dep_name = dep_spec.split(SEPARATOR, 2)
52
+ source_for(source_name).find(dep_name)
53
+ elsif opts[:from]
54
+ opts[:from].find(dep_spec) || dep_for(dep_spec)
55
+ else # Otherwise, load from the current source (opts[:from]) or the standard set.
56
+ matches = Base.sources.current.map {|source| source.find(dep_spec) }.flatten.compact
57
+ if matches.length > 1
58
+ log "Multiple sources (#{matches.map(&:dep_source).map(&:name).join(',')}) contain a dep called '#{dep_spec}'."
59
+ else
60
+ matches.first
61
+ end
62
+ end
63
+ end
64
+
65
+ def template_for template_spec, opts = {}
66
+ if template_spec.nil?
67
+ nil
68
+ elsif template_spec[/#{SEPARATOR}/] # If a source was specified, that's where we load from.
69
+ source_name, template_name = template_spec.split(SEPARATOR, 2)
70
+ source_for(source_name).find_template(template_name)
71
+ elsif opts[:from]
72
+ opts[:from].find_template(template_spec) || template_for(template_spec)
73
+ else
74
+ matches = Base.sources.default.map {|source| source.find_template(template_spec) }.flatten.compact
75
+ if matches.length > 1
76
+ log "Multiple sources (#{matches.map(&:source).map(&:name).join(',')}) contain a template called '#{template_name}'."
77
+ else
78
+ matches.first
79
+ end
80
+ end
81
+ end
82
+
83
+ def update!
84
+ all_present.select {|source|
85
+ source.cloneable?
86
+ }.tap {|sources|
87
+ log "Updating #{sources.length} source#{'s' unless sources.length == 1}."
88
+ }.map {|source|
89
+ source.update!
90
+ }.all?
91
+ end
92
+
93
+ def list!
94
+ Logging.log_table(
95
+ ['Name', 'Source path', 'Type', 'Last updated'],
96
+ Source.present.tap {|sources|
97
+ log "There #{sources.length == 1 ? 'is' : 'are'} #{sources.length} source#{'s' unless sources.length == 1} in #{Source.source_prefix}:"
98
+ log ''
99
+ }.map(&:description_pieces)
100
+ )
101
+ end
102
+
103
+ def uncache!
104
+ current.each {|source| source.deps.uncache! }
105
+ end
106
+
107
+ def local_only?
108
+ @local_only
109
+ end
110
+
111
+ def local_only &block
112
+ previously = @local_only
113
+ @local_only = true
114
+ yield
115
+ ensure
116
+ @local_only = previously
117
+ end
118
+
119
+ def load_context context, &block
120
+ (@load_contexts ||= []).push context
121
+ yield
122
+ ensure
123
+ @load_contexts.pop
124
+ end
125
+
126
+ def current_real_load_source
127
+ current_load_context[:source]
128
+ end
129
+ def current_load_source
130
+ current_real_load_source || Base.sources.anonymous
131
+ end
132
+ def current_load_path
133
+ current_load_context[:path].try(:p)
134
+ end
135
+ def current_load_opts
136
+ current_load_context[:opts] || {}
137
+ end
138
+
139
+ private
140
+
141
+ def current_load_context
142
+ (@load_contexts ||= []).last || {}
143
+ end
144
+
145
+ end
146
+ end
@@ -0,0 +1,97 @@
1
+ module Babushka
2
+ class SystemDefinitions
3
+ def self.all_systems
4
+ names.keys
5
+ end
6
+ def self.all_flavours
7
+ names.values.map(&:keys).flatten
8
+ end
9
+ def self.all_names
10
+ names.values.map(&:values).map {|s| s.map(&:values) }.flatten
11
+ end
12
+ def self.all_tokens
13
+ all_systems + PkgHelper.all_manager_keys + all_flavours + all_names
14
+ end
15
+
16
+ def self.names
17
+ {
18
+ :osx => {
19
+ :osx => {
20
+ '10.3' => :panther,
21
+ '10.4' => :tiger,
22
+ '10.5' => :leopard,
23
+ '10.6' => :snow_leopard,
24
+ '10.7' => :lion
25
+ }
26
+ },
27
+ :linux => {
28
+ :ubuntu => {
29
+ '4.10' => :warty,
30
+ '5.04' => :hoary,
31
+ '5.10' => :breezy,
32
+ '6.06' => :dapper,
33
+ '6.10' => :edgy,
34
+ '7.04' => :feisty,
35
+ '7.10' => :gutsy,
36
+ '8.04' => :hardy,
37
+ '8.10' => :intrepid,
38
+ '9.04' => :jaunty,
39
+ '9.10' => :karmic,
40
+ '10.04' => :lucid,
41
+ '10.10' => :maverick,
42
+ '11.04' => :natty
43
+ },
44
+ :debian => {
45
+ '4.0' => :etch,
46
+ '5.0' => :lenny,
47
+ '6.0' => :squeeze,
48
+ '7.0' => :wheezy
49
+ }
50
+ },
51
+ :bsd => {
52
+ :dragonfly => {},
53
+ :freebsd => {}
54
+ }
55
+ }
56
+ end
57
+
58
+ def self.descriptions
59
+ {
60
+ :osx => {
61
+ :osx => {
62
+ '10.3' => 'Panther',
63
+ '10.4' => 'Tiger',
64
+ '10.5' => 'Leopard',
65
+ '10.6' => 'Snow Leopard',
66
+ '10.7' => 'Lion'
67
+ }
68
+ },
69
+ :linux => {
70
+ :ubuntu => {
71
+ '4.10' => 'Warty Warthog',
72
+ '5.04' => 'Hoary Hedgehog',
73
+ '5.10' => 'Breezy Badger',
74
+ '6.06' => 'Dapper Drake',
75
+ '6.10' => 'Edgy Eft',
76
+ '7.04' => 'Feisty Fawn',
77
+ '7.10' => 'Gutsy Gibbon',
78
+ '8.04' => 'Hardy Heron',
79
+ '8.10' => 'Intrepid Ibex',
80
+ '9.04' => 'Jaunty Jackalope',
81
+ '9.10' => 'Karmic Koala',
82
+ '10.04' => 'Lucid Lynx',
83
+ '10.10' => 'Maverick Meerkat',
84
+ '11.04' => 'Natty Narwhal'
85
+ },
86
+ :debian => {
87
+ '5.0.4' => 'Lenny'
88
+ }
89
+ },
90
+ :bsd => {
91
+ :dragonfly => {},
92
+ :freebsd => {}
93
+ }
94
+ }
95
+ end
96
+ end
97
+ end