devstructure 0.4.0 → 0.5.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.
@@ -235,8 +235,7 @@ EOF
235
235
 
236
236
  # This is the Puppet code generator.
237
237
  def puppet(io=StringIO.new)
238
- io.puts disclaimer
239
- manifest = Puppet::Manifest.new(@name)
238
+ manifest = Puppet::Manifest.new(@name, nil, disclaimer)
240
239
 
241
240
  # Right out of the gate, we set a default `PATH` because Puppet does not.
242
241
  manifest << Puppet::Exec.defaults(:path => ENV["PATH"].split(":"))
@@ -264,7 +263,7 @@ EOF
264
263
  if 0 < classes.length
265
264
  manifest << Puppet::File.defaults(:before => classes)
266
265
  end
267
- files.sort.each do |pathname, content|
266
+ files.each do |pathname, content|
268
267
 
269
268
  # Resources for all parent directories are created ahead of
270
269
  # any file. Puppet's autorequire mechanism will ensure that a
@@ -272,7 +271,7 @@ EOF
272
271
  dirnames = File.dirname(pathname).split("/")
273
272
  dirnames.shift
274
273
  (0..(dirnames.length - 1)).each do |i|
275
- manifest << Puppet::File.new("/#{dirnames[0..i].join("/")}",
274
+ manifest << Puppet::File.new("/#{dirnames[0..i].join("/")}", nil,
276
275
  :ensure => :directory)
277
276
  end
278
277
 
@@ -284,10 +283,12 @@ EOF
284
283
  options[:group] = content["_group"] if content["_group"]
285
284
  if content["_target"]
286
285
  options[:ensure] = content["_target"]
286
+ content = nil
287
287
  else
288
288
  options[:mode] = content["_mode"] if content["_mode"]
289
289
  options[:ensure] = :file
290
- options[:content] = if content["_base64"]
290
+ options[:content] = :"template(\"#{manifest.name}#{pathname}\")"
291
+ content = if content["_base64"]
291
292
  Base64.decode64(content["_base64"])
292
293
  else
293
294
  content["_content"]
@@ -299,12 +300,12 @@ EOF
299
300
  # be set according to the `umask`.
300
301
  else
301
302
  options = {
302
- :content => content,
303
+ :content => :"template(\"#{manifest.name}#{pathname}\")",
303
304
  :ensure => :file,
304
305
  }
305
306
  end
306
307
 
307
- manifest << Puppet::File.new(pathname, options)
308
+ manifest << Puppet::File.new(pathname, content, options)
308
309
  end
309
310
  end
310
311
 
@@ -426,7 +427,7 @@ EOF
426
427
  # such as this in a shell invocation. This is a pretty direct Puppet
427
428
  # equivalent to the shell version above.
428
429
  if sources && 0 < sources.length
429
- sources.sort.each do |dirname, filename|
430
+ sources.each do |dirname, filename|
430
431
  manifest << Puppet::Exec.new(filename,
431
432
  :command => "/bin/sh -c 'wget http://s3.amazonaws.com/blueprint-sources/#{filename}; tar xf #{filename}; rm #{filename}'",
432
433
  :cwd => dirname
@@ -434,9 +435,10 @@ EOF
434
435
  end
435
436
  end
436
437
 
437
- io.puts manifest
438
- io.close
439
- io
438
+ # Generate a module tarball containing the manifest and any templates
439
+ # needed to compile a catalog that includes this module.
440
+ manifest.to_gz(io)
441
+
440
442
  end
441
443
 
442
444
  # This is the Chef code generator. It is the first of its kind in
@@ -1,6 +1,6 @@
1
1
  # The Chef code generator is structured much like the shell code generator
2
2
  # because Chef doesn't include any sort of dependency management like
3
- # Puppet. As expected, we'll start with packages, follow them with files,
3
+ # Puppet. As expected, we'll start with files, follow them with packages,
4
4
  # and finish with source tarballs.
5
5
  #
6
6
  # The monkeywrench is that the ultimate output is a tarball of a Chef
@@ -94,20 +94,20 @@ module Chef
94
94
  :mtime => mtime
95
95
  }) { |w| w.write resources }
96
96
 
97
- # Included any files referenced by `cookbook_file` resources. They
97
+ # Include any files referenced by `cookbook_file` resources. They
98
98
  # all appear in `files/default/` as if that is the root of the
99
99
  # filesystem.
100
100
  if 0 < @files.length
101
101
  tar.mkdir "#{@name}/files", :mode => 0755, :mtime => mtime
102
102
  tar.mkdir "#{@name}/files/default", :mode => 0755, :mtime => mtime
103
- @files.each do |name, content|
104
- dirnames = File.dirname(name).split("/")
103
+ @files.each do |pathname, content|
104
+ dirnames = File.dirname(pathname).split("/")
105
105
  dirnames.shift
106
106
  (0..(dirnames.length - 1)).each do |i|
107
107
  tar.mkdir "#{@name}/files/default/#{dirnames[0..i].join("/")}",
108
108
  :mode => 0755, :mtime => mtime
109
109
  end
110
- tar.add_file_simple("#{@name}/files/default#{name}", {
110
+ tar.add_file_simple("#{@name}/files/default#{pathname}", {
111
111
  :mode => 0644,
112
112
  :size => content.length,
113
113
  :mtime => mtime
@@ -14,6 +14,13 @@
14
14
  # [sandbox-blueprint]: http://devstructure.github.com/contractor/sandbox-blueprint.1.html
15
15
  require 'devstructure'
16
16
 
17
+ # Unfortunately, RubyGems rears its ugly head. The call to `gem` here is
18
+ # just because the gem's name is different than the path being `require`d.
19
+ gem 'archive-tar-minitar', :require => 'archive/tar/minitar'
20
+ require 'archive/tar/minitar'
21
+
22
+ require 'zlib'
23
+
17
24
  # Make `Symbol`s and `nil`s `Comparable` so we can sort each list of resource
18
25
  # attributes before converting to a string.
19
26
  class Symbol
@@ -37,11 +44,13 @@ module DevStructure::Puppet
37
44
 
38
45
  # Each class must have a name and might have a parent. If a manifest
39
46
  # has a parent, this signals it to `include` itself in the parent.
40
- def initialize(name, parent=nil)
41
- @name, @parent = name, parent
47
+ def initialize(name, parent=nil, comment=nil)
48
+ @name, @parent, @comment = name.gsub(".", "--"), parent, comment
42
49
  @manifests, @resources = {}, {}
43
50
  end
44
51
 
52
+ attr_reader :name
53
+
45
54
  # Manifests behave a bit like hashes in that their children can be
46
55
  # traversed. Note the children can't be assigned directly because
47
56
  # we must maintain parent-child relationships.
@@ -68,6 +77,18 @@ module DevStructure::Puppet
68
77
  end
69
78
  end
70
79
 
80
+ # Return a hash of `pathname`s to `content`s for all the templates
81
+ # referenced in this manifest. `file` resources which define the
82
+ # `content` attribute must have a template containing the file itself.
83
+ def templates
84
+ out = {}
85
+ (@resources["file"] || {}).select do |name, resource|
86
+ next unless resource[:content] && resource.content
87
+ out[name] = resource.content
88
+ end
89
+ out
90
+ end
91
+
71
92
  # Turn this manifest into a Puppet class. We start with a base level
72
93
  # of indentation that we carry through our resources and manifests.
73
94
  # Order is again not important so we don't make much effort. The
@@ -80,7 +101,8 @@ module DevStructure::Puppet
80
101
  # ourselves in the parent.
81
102
  def to_s(tab="")
82
103
  out = []
83
- out << "#{tab}class #{@name.gsub(".", "--")} {"
104
+ out << @comment if @comment
105
+ out << "#{tab}class #{@name} {"
84
106
  @manifests.each_value do |manifest|
85
107
  out << manifest.to_s("#{tab}\t")
86
108
  end
@@ -100,10 +122,54 @@ module DevStructure::Puppet
100
122
  end
101
123
  end
102
124
  out << "#{tab}}"
103
- out << "#{tab}include #{@name.gsub(".", "--")}" if @parent
125
+ out << "#{tab}include #{@name}" if @parent
104
126
  out.join("\n")
105
127
  end
106
128
 
129
+ # Create a Puppet module containing a manifest and the files being
130
+ # distributed as templates.
131
+ def to_gz(io)
132
+ mtime = Time.now
133
+ gz = Zlib::GzipWriter.new(io)
134
+ tar = Archive::Tar::Minitar::Writer.new(gz)
135
+ tar.mkdir @name, :mode => 0755, :mtime => mtime
136
+
137
+ # Store the manifest in the tarball.
138
+ manifest = to_s
139
+ tar.mkdir "#{@name}/manifests", :mode => 0755, :mtime => mtime
140
+ tar.add_file_simple("#{@name}/manifests/init.pp", {
141
+ :mode => 0644,
142
+ :size => manifest.length,
143
+ :mtime => mtime
144
+ }) { |w| w.write manifest }
145
+
146
+ # Include as templates the content of any files in the module.
147
+ templates = self.templates
148
+ @manifests.each_value { |manifest| templates.merge! manifest.templates }
149
+ if 0 < templates.length
150
+ tar.mkdir "#{@name}/templates", :mode => 0755, :mtime => mtime
151
+ templates.each do |pathname, content|
152
+ dirnames = ::File.dirname(pathname).split("/")
153
+ dirnames.shift
154
+ (0..(dirnames.length - 1)).each do |i|
155
+ tar.mkdir "#{@name}/templates/#{dirnames[0..i].join("/")}",
156
+ :mode => 0755, :mtime => mtime
157
+ end
158
+ tar.add_file_simple("#{@name}/templates#{pathname}", {
159
+ :mode => 0644,
160
+ :size => content.length,
161
+ :mtime => mtime
162
+ }) { |w| w.write content }
163
+ end
164
+ end
165
+
166
+ # Return the finalized tarball.
167
+ tar.close
168
+ gz.close
169
+ io
170
+
171
+ end
172
+
107
173
  end
108
174
 
109
175
  # A Puppet resource is basically a named hash. The name is unique
@@ -113,12 +179,13 @@ module DevStructure::Puppet
113
179
  # name to determine the type, so do not instantiate `Resource`
114
180
  # directly.
115
181
  class Resource < Hash
116
- attr_accessor :type, :name, :style
182
+ attr_reader :type
183
+ attr_accessor :name, :style
117
184
 
118
185
  def initialize(name, options={})
119
186
  super nil
120
187
  clear
121
- options.each { |k, v| self[k.to_s] = v }
188
+ options.each { |k, v| self[k.to_sym] = v }
122
189
  @type = self.class.to_s.downcase[/[^:]+$/]
123
190
  @name = name && name.to_s
124
191
  @style = :complete
@@ -237,7 +304,16 @@ module DevStructure::Puppet
237
304
  # type. The most common types are `Package`, `Exec`, and `File`.
238
305
  class Package < Resource; end
239
306
  class Exec < Resource; end
240
- class File < Resource; end
307
+
308
+ # `File` resources are a special because they need their content stored
309
+ # in a template.
310
+ class File < Resource
311
+ def initialize(name, content, options={})
312
+ super name, options
313
+ @content = content
314
+ end
315
+ attr_reader :content
316
+ end
241
317
 
242
318
  # `Class` is also a useful resource type but needs a little more help
243
319
  # because of the stricter rules governing class names in the Puppet
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devstructure
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 4
8
+ - 5
9
9
  - 0
10
- version: 0.4.0
10
+ version: 0.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Richard Crowley
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-19 00:00:00 +00:00
18
+ date: 2010-10-05 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency