1
1
require 'tempfile'
2
2
3
3
OUTPUT_DIR = 'references'
4
+ MANDIR = File . join ( OUTPUT_DIR , 'man' )
5
+ TYPES_DIR = File . join ( OUTPUT_DIR , 'types' )
6
+
4
7
CONFIGURATION_ERB = File . join ( __dir__ , 'references/configuration.erb' )
5
8
CONFIGURATION_MD = File . join ( OUTPUT_DIR , 'configuration.md' )
6
9
METAPARAMETER_ERB = File . join ( __dir__ , 'references/metaparameter.erb' )
@@ -10,6 +13,14 @@ REPORT_MD = File.join(OUTPUT_DIR, 'report.md')
10
13
FUNCTIONS_TEMPLATE_ERB = File . join ( __dir__ , 'references/functions_template.erb' )
11
14
FUNCTION_ERB = File . join ( __dir__ , 'references/function.erb' )
12
15
FUNCTION_MD = File . join ( OUTPUT_DIR , 'function.md' )
16
+ MAN_OVERVIEW_ERB = File . join ( __dir__ , 'references/man/overview.erb' )
17
+ MAN_OVERVIEW_MD = File . join ( MANDIR , "overview.md" )
18
+ MAN_ERB = File . join ( __dir__ , 'references/man.erb' )
19
+ TYPES_OVERVIEW_ERB = File . join ( __dir__ , 'references/types/overview.erb' )
20
+ TYPES_OVERVIEW_MD = File . join ( TYPES_DIR , 'overview.md' )
21
+ UNIFIED_TYPE_ERB = File . join ( __dir__ , 'references/unified_type.erb' )
22
+ UNIFIED_TYPE_MD = File . join ( OUTPUT_DIR , 'type.md' )
23
+ SINGLE_TYPE_ERB = File . join ( __dir__ , 'references/types/single_type.erb' )
13
24
14
25
def render_erb ( erb_file , variables )
15
26
# Create a binding so only the variables we specify will be visible
@@ -38,6 +49,134 @@ def generate_reference(reference, erb, body, output)
38
49
puts "Generated #{ output } "
39
50
end
40
51
52
+ # Render type information for the specified resource type
53
+ # Based on https://github.com/puppetlabs/puppet-docs/blob/1a13be3fc6981baa8a96ff832ab090abc986830e/lib/puppet_references/puppet/type.rb#L87-L112
54
+ def render_resource_type ( name , this_type )
55
+ sorted_attribute_list = this_type [ 'attributes' ] . keys . sort { |a , b |
56
+ # Float namevar(s) to the top and ensure after
57
+ # followed by the others in sort order
58
+ if this_type [ 'attributes' ] [ a ] [ 'namevar' ]
59
+ -1
60
+ elsif this_type [ 'attributes' ] [ b ] [ 'namevar' ]
61
+ 1
62
+ elsif a == 'ensure'
63
+ -1
64
+ elsif b == 'ensure'
65
+ 1
66
+ else
67
+ a <=> b
68
+ end
69
+ }
70
+
71
+ variables = {
72
+ name : name ,
73
+ this_type : this_type ,
74
+ sorted_attribute_list : sorted_attribute_list ,
75
+ sorted_feature_list : this_type [ 'features' ] . keys . sort ,
76
+ longest_attribute_name : sorted_attribute_list . collect { |attr | attr . length } . max
77
+ }
78
+ erb = File . join ( __dir__ , 'references/types/type.erb' )
79
+ render_erb ( erb , variables )
80
+ end
81
+
82
+ # Based on https://github.com/puppetlabs/puppet-docs/blob/1a13be3fc6981baa8a96ff832ab090abc986830e/lib/puppet_references/puppet/type_strings.rb#L19-L99
83
+ def extract_resource_types ( strings_data )
84
+ strings_data [ 'resource_types' ] . reduce ( Hash . new ) do |memo , type |
85
+ memo [ type [ 'name' ] ] = {
86
+ 'description' => type [ 'docstring' ] [ 'text' ] ,
87
+ 'features' => ( type [ 'features' ] || [ ] ) . reduce ( Hash . new ) { |memo , feature |
88
+ memo [ feature [ 'name' ] ] = feature [ 'description' ]
89
+ memo
90
+ } ,
91
+ 'providers' => strings_data [ 'providers' ] . select { |provider |
92
+ provider [ 'type_name' ] == type [ 'name' ]
93
+ } . reduce ( Hash . new ) { |memo , provider |
94
+ description = provider [ 'docstring' ] [ 'text' ]
95
+ if provider [ 'commands' ] || provider [ 'confines' ] || provider [ 'defaults' ]
96
+ description = description + "\n "
97
+ end
98
+ if provider [ 'commands' ]
99
+ description = description + "\n * Required binaries: `#{ provider [ 'commands' ] . values . sort . join ( '`, `' ) } `"
100
+ end
101
+ if provider [ 'confines' ]
102
+ description = description + "\n * Confined to: `#{ provider [ 'confines' ] . map { |fact , val | "#{ fact } == #{ val } " } . join ( '`, `' ) } `"
103
+ end
104
+ if provider [ 'defaults' ]
105
+ description = description + "\n * Default for: `#{ provider [ 'defaults' ] . map { |fact , val | "#{ fact } == #{ val } " } . join ( '`, `' ) } `"
106
+ end
107
+ if provider [ 'features' ]
108
+ description = description + "\n * Supported features: `#{ provider [ 'features' ] . sort . join ( '`, `' ) } `"
109
+ end
110
+ memo [ provider [ 'name' ] ] = {
111
+ 'features' => ( provider [ 'features' ] || [ ] ) ,
112
+ 'description' => description
113
+ }
114
+ memo
115
+ } ,
116
+ 'attributes' => ( type [ 'parameters' ] || [ ] ) . reduce ( Hash . new ) { |memo , attribute |
117
+ description = attribute [ 'description' ] || ''
118
+ if attribute [ 'default' ]
119
+ description = description + "\n \n Default: `#{ attribute [ 'default' ] } `"
120
+ end
121
+ if attribute [ 'values' ]
122
+ description = description + "\n \n Allowed values:\n \n " + attribute [ 'values' ] . map { |val | "* `#{ val } `" } . join ( "\n " )
123
+ end
124
+ memo [ attribute [ 'name' ] ] = {
125
+ 'description' => description ,
126
+ 'kind' => 'parameter' ,
127
+ 'namevar' => attribute [ 'isnamevar' ] ? true : false ,
128
+ 'required_features' => attribute [ 'required_features' ] ,
129
+ }
130
+ memo
131
+ } . merge ( ( type [ 'properties' ] || [ ] ) . reduce ( Hash . new ) { |memo , attribute |
132
+ description = attribute [ 'description' ] || ''
133
+ if attribute [ 'default' ]
134
+ description = description + "\n \n Default: `#{ attribute [ 'default' ] } `"
135
+ end
136
+ if attribute [ 'values' ]
137
+ description = description + "\n \n Allowed values:\n \n " + attribute [ 'values' ] . map { |val | "* `#{ val } `" } . join ( "\n " )
138
+ end
139
+ memo [ attribute [ 'name' ] ] = {
140
+ 'description' => description ,
141
+ 'kind' => 'property' ,
142
+ 'namevar' => false ,
143
+ 'required_features' => attribute [ 'required_features' ] ,
144
+ }
145
+ memo
146
+ } ) . merge ( ( type [ 'checks' ] || [ ] ) . reduce ( Hash . new ) { |memo , attribute |
147
+ description = attribute [ 'description' ] || ''
148
+ if attribute [ 'default' ]
149
+ description = description + "\n \n Default: `#{ attribute [ 'default' ] } `"
150
+ end
151
+ if attribute [ 'values' ]
152
+ description = description + "\n \n Allowed values:\n \n " + attribute [ 'values' ] . map { |val | "* `#{ val } `" } . join ( "\n " )
153
+ end
154
+ memo [ attribute [ 'name' ] ] = {
155
+ 'description' => description ,
156
+ 'kind' => 'check' ,
157
+ 'namevar' => false ,
158
+ 'required_features' => attribute [ 'required_features' ] ,
159
+ }
160
+ memo
161
+ } )
162
+ }
163
+ memo
164
+ end
165
+ end
166
+
167
+ # Extract type documentation from the current version of puppet. Based on
168
+ # https://github.com/puppetlabs/puppet-docs/blob/1a13be3fc6981baa8a96ff832ab090abc986830e/lib/puppet_references/puppet/type.rb#L52
169
+ #
170
+ # REMIND This is kind of convoluted and means we're using two completely different
171
+ # code paths to generate the overview and unified page of types.
172
+ def unified_page_resource_types
173
+ type_json = %x{ruby #{ File . join ( __dir__ , 'references/get_typedocs.rb' ) } }
174
+ type_data = JSON . load ( type_json )
175
+ type_data . keys . sort . map do |name |
176
+ render_resource_type ( name , type_data [ name ] )
177
+ end
178
+ end
179
+
41
180
namespace :references do
42
181
desc "Generate configuration reference"
43
182
task :configuration do
@@ -100,4 +239,179 @@ namespace :references do
100
239
# renders the preamble and list of functions
101
240
generate_reference ( 'function' , FUNCTION_ERB , body , FUNCTION_MD )
102
241
end
242
+
243
+ desc "Generate man as markdown references"
244
+ task :man do
245
+ FileUtils . mkdir_p ( MANDIR )
246
+
247
+ begin
248
+ require 'pandoc-ruby'
249
+ rescue LoadError
250
+ abort ( "Run `bundle config set with documentation` and `bundle update` to install the `pandoc-ruby` gem." )
251
+ end
252
+
253
+ pandoc = %x{which pandoc} . chomp
254
+ unless File . executable? ( pandoc )
255
+ abort ( "Please install the `pandoc` package." )
256
+ end
257
+
258
+ sha = %x{git rev-parse HEAD} . chomp
259
+ now = Time . now
260
+
261
+ # This is based on https://github.com/puppetlabs/puppet-docs/blob/1a13be3fc6981baa8a96ff832ab090abc986830e/lib/puppet_references/puppet/man.rb#L24-L108
262
+ core_apps = %w(
263
+ agent
264
+ apply
265
+ lookup
266
+ module
267
+ resource
268
+ )
269
+ occasional_apps = %w(
270
+ config
271
+ describe
272
+ device
273
+ doc
274
+ epp
275
+ generate
276
+ help
277
+ node
278
+ parser
279
+ plugin
280
+ script
281
+ ssl
282
+ )
283
+ weird_apps = %w(
284
+ catalog
285
+ facts
286
+ filebucket
287
+ report
288
+ )
289
+
290
+ variables = {
291
+ sha : sha ,
292
+ now : now ,
293
+ title : 'Puppet Man Pages' ,
294
+ core_apps : core_apps ,
295
+ occasional_apps : occasional_apps ,
296
+ weird_apps : weird_apps
297
+ }
298
+
299
+ content = render_erb ( MAN_OVERVIEW_ERB , variables )
300
+ File . write ( MAN_OVERVIEW_MD , content )
301
+ puts "Generated #{ MAN_OVERVIEW_MD } "
302
+
303
+ # Generate manpages in roff
304
+ Rake ::Task [ :gen_manpages ] . invoke
305
+
306
+ # Convert the roff formatted man pages to markdown, based on
307
+ # https://github.com/puppetlabs/puppet-docs/blob/1a13be3fc6981baa8a96ff832ab090abc986830e/lib/puppet_references/puppet/man.rb#L119-L128
308
+ files = Pathname . glob ( File . join ( __dir__ , '../man/man8/*.8' ) )
309
+ files . each do |f |
310
+ next if File . basename ( f ) == "puppet.8"
311
+
312
+ app = File . basename ( f ) . delete_prefix ( 'puppet-' ) . delete_suffix ( ".8" )
313
+
314
+ body =
315
+ PandocRuby . convert ( [ f ] , from : :man , to : :markdown )
316
+ . gsub ( /#(.*?)\n / , '##\1' )
317
+ . gsub ( /:\s \s \s \n \n ```\{ =html\} \n <!--\s -->\n ```/ , '' )
318
+ . gsub ( /\n :\s \s \s \s / , '' )
319
+ . chomp
320
+
321
+ variables = {
322
+ sha : sha ,
323
+ now : now ,
324
+ title : "Man Page: puppet #{ app } " ,
325
+ canonical : "/puppet/latest/man/#{ app } .html" ,
326
+ body : body
327
+ }
328
+
329
+ content = render_erb ( MAN_ERB , variables )
330
+ output = File . join ( MANDIR , "#{ app } .md" )
331
+ File . write ( output , content )
332
+ puts "Generated #{ output } "
333
+ end
334
+ end
335
+
336
+ desc "Generate resource type references"
337
+ task :type do
338
+ FileUtils . mkdir_p ( TYPES_DIR )
339
+
340
+ # Locate puppet-strings
341
+ begin
342
+ require 'puppet-strings'
343
+ require 'puppet-strings/version'
344
+ rescue LoadError
345
+ abort ( "Run `bundle config set with documentation` and `bundle update` to install the `puppet-strings` gem." )
346
+ end
347
+
348
+ sha = %x{git rev-parse HEAD} . chomp
349
+ now = Time . now
350
+
351
+ # Based on https://github.com/puppetlabs/puppet-docs/blob/1a13be3fc6981baa8a96ff832ab090abc986830e/lib/puppet_references/puppet/strings.rb#L25-L26
352
+ Tempfile . create do |tmpfile |
353
+ puts "Running puppet strings #{ PuppetStrings ::VERSION } "
354
+ PuppetStrings . generate ( [ 'lib/puppet/type/*.rb' ] , json : true , path : tmpfile . path )
355
+ strings_data = JSON . load_file ( tmpfile . path )
356
+
357
+ # convert strings output to data the overview ERB template expects
358
+ type_data = extract_resource_types ( strings_data )
359
+
360
+ # Generate overview.md
361
+ # Based on https://github.com/puppetlabs/puppet-docs/blob/1a13be3fc6981baa8a96ff832ab090abc986830e/lib/puppet_references/puppet/type.rb#L40-L47
362
+ types = type_data . keys . reject do |type |
363
+ type == 'component' || type == 'whit'
364
+ end
365
+
366
+ variables = {
367
+ title : 'Resource types overview' ,
368
+ sha : sha ,
369
+ now : now ,
370
+ types : types
371
+ }
372
+
373
+ # Render overview page
374
+ content = render_erb ( TYPES_OVERVIEW_ERB , variables )
375
+ File . write ( TYPES_OVERVIEW_MD , content )
376
+ puts "Generated #{ TYPES_OVERVIEW_MD } "
377
+
378
+ # Based on https://github.com/puppetlabs/puppet-docs/blob/1a13be3fc6981baa8a96ff832ab090abc986830e/lib/puppet_references/puppet/type.rb#L55-L70
379
+ # unified page of types
380
+ variables = {
381
+ title : 'Resource Type Reference (Single-Page)' ,
382
+ sha : sha ,
383
+ now : now ,
384
+ types : unified_page_resource_types
385
+ }
386
+
387
+ content = render_erb ( UNIFIED_TYPE_ERB , variables )
388
+ File . write ( UNIFIED_TYPE_MD , content )
389
+ puts "Generated #{ UNIFIED_TYPE_MD } "
390
+
391
+ # Based on https://github.com/puppetlabs/puppet-docs/blob/1a13be3fc6981baa8a96ff832ab090abc986830e/lib/puppet_references/puppet/type.rb#L78-L85
392
+ # one type per page
393
+ types . each do |type |
394
+ variables = {
395
+ title : "Resource Type: #{ type } " ,
396
+ type : type ,
397
+ sha : sha ,
398
+ now : now ,
399
+ canonical : "/puppet/latest/types/#{ type } .html" ,
400
+ body : render_resource_type ( type , type_data [ type ] )
401
+ }
402
+
403
+ content = render_erb ( SINGLE_TYPE_ERB , variables )
404
+ output = File . join ( TYPES_DIR , "#{ type } .md" )
405
+ File . write ( output , content )
406
+ puts "Generated #{ output } "
407
+ end
408
+ end
409
+ end
410
+
411
+ desc "Generate all reference documentation"
412
+ task :all do
413
+ %w[ configuration function report metaparameter man type ] . each do |ref |
414
+ Rake ::Task [ "references:#{ ref } " ] . invoke
415
+ end
416
+ end
103
417
end
0 commit comments