#!/usr/bin/env ruby # # = Synopsis # # Generate a reference for all Puppet types. Largely meant for internal Reductive # Labs use. # # = Usage # # puppetdoc [-h|--help] [-a|--arguments] [-t|--types] # # = Description # # This command generates a restructured-text document describing all installed # Puppet types or all allowable arguments to puppet executables. It is largely # meant for internal use and is used to generate the reference document # available on the Reductive Labs web site. # # = Options # # arguments:: # Print the documentation for arguments. # # help:: # Print this help message # # types:: # Print the argumenst for Puppet types. This is the default. # # = Example # # $ puppetdoc > /tmp/reference.rst # # = Author # # Luke Kanies # # = Copyright # # Copyright (c) 2005 Reductive Labs, LLC # Licensed under the GNU Public License require 'puppet' require 'getoptlong' $haveusage = true begin require 'rdoc/usage' rescue Exception $haveusage = false end result = GetoptLong.new( [ "--arguments", "-a", GetoptLong::NO_ARGUMENT ], [ "--types", "-t", GetoptLong::NO_ARGUMENT ], [ "--help", "-h", GetoptLong::NO_ARGUMENT ] ) debug = false $tab = " " mode = :types begin result.each { |opt,arg| case opt when "--arguments" mode = :arguments when "--types" mode = :types when "--help" if $haveusage RDoc::usage && exit else puts "No help available unless you have RDoc::usage installed" exit end end } rescue GetoptLong::InvalidOption => detail $stderr.puts "Try '#{$0} --help'" #if $haveusage # RDoc::usage_no_exit('usage') #end exit(1) end def scrub(text) # Stupid markdown #text = text.gsub("<%=", "<%=") # For text with no carriage returns, there's nothing to do. if text !~ /\n/ return text end indent = nil # If we can match an indentation, then just remove that same level of # indent from every line. if text =~ /^(\s+)/ indent = $1 begin return text.gsub(/^#{indent}/,'') rescue => detail puts detail.backtrace puts detail end else return text end end # Indent every line in the chunk except those which begin with '..'. def indent(text, tab) return text.gsub(/(^|\A)/, tab).gsub(/^ +\.\./, "..") end def paramwrap(name, text, namevar = false) if namevar name = name.to_s + " (*namevar*)" end puts "#### %s" % name puts text puts "" end # Print the docs for arguments def self.arguments puts %{--- inMenu: true title: Configuration Reference orderInfo: 6 --- # Puppet Configuration Reference Every Puppet executable (with the exception of ``puppetdoc``) accepts all of these arguments, but not all of the arguments make sense for every executable. Each argument has a section listed with it in parentheses; often, that section will map to an executable (e.g., ``puppetd``), in which case it probably only makes sense for that one executable. If ``puppet`` is listed as the section, it is most likely an option that is valid for everyone. This will not always be the case. I have tried to be as thorough as possible in the descriptions of the arguments, so it should be obvious whether an argument is approprite or not. Any default values are in ``block type`` at the end of the description. } docs = {} Puppet.config.each do |name, object| docs[name] = object end docs.sort { |a, b| a[0].to_s <=> b[0].to_s }.each do |name, object| # Make each name an anchor puts %{#### #{name.to_s} (#{object.section.to_s})} puts "" default = "" if val = object.value and val != "" default = " ``%s``" % val end begin puts object.desc.gsub(/\n/, " ") + default rescue => detail puts detail.backtrace puts detail end puts "" end end # Print the docs for types def self.types puts %{--- inMenu: true title: Type Reference orderInfo: 4 --- # Type Reference } types = {} Puppet::Type.loadall Puppet::Type.eachtype { |type| next if type.name == :puppet next if type.name == :component types[type.name] = type } # Build a simple TOC puts "## Table of Contents" puts "1. Meta-Parameters" types.sort { |a, b| a[0].to_s <=> b[0].to_s }.each do |name, type| puts "1. %s" % [type.name, type.name.to_s.capitalize] end puts %{

Meta-Parameters

Metaparameters are parameters that work with any element; they are part of the Puppet framework itself rather than being part of the implementation of any given instance. Thus, any defined metaparameter can be used with any instance in your manifest, including defined components. } begin params = [] Puppet::Type.eachmetaparam { |param| params << param } params.sort { |a,b| a.to_s <=> b.to_s }.each { |param| paramwrap(param.to_s, scrub(Puppet::Type.metaparamdoc(param))) #puts "
" + param.to_s + "
" #puts tab(1) + Puppet::Type.metaparamdoc(param).scrub.indent($tab)gsub(/\n\s*/,' ') #puts "
" #puts indent(scrub(Puppet::Type.metaparamdoc(param)), $tab) #puts scrub(Puppet::Type.metaparamdoc(param)) #puts "
" #puts "" } rescue => detail puts detail.backtrace puts "incorrect metaparams: %s" % detail exit(1) end puts %{ ## Types - *namevar* is the parameter used to uniquely identify a type instance. This is the parameter that gets assigned when a string is provided before the colon in a type declaration. In general, only developers will need to worry about which parameter is the ``namevar``. In the following code: file { "/etc/passwd": owner => root, group => root, mode => 644 } "/etc/passwd" is considered the name of the file object (used for things like dependency handling), and because ``path`` is the namevar for ``file``, that string is assigned to the ``path`` parameter. - *parameters* determine the specific configuration of the instance. They either directly modify the system (internally, these are called states) or they affect how the instance behaves (e.g., adding a search path for ``exec`` instances or determining recursion on ``file`` instances). When required binaries are specified for providers, fully qualifed paths indicate that the binary must exist at that specific path and unqualified binaries indicate that Puppet will search for the binary using the shell path. } types.sort { |a,b| a.to_s <=> b.to_s }.each { |name,type| puts " ---------------- " puts "

%s

" % [name, name] puts scrub(type.doc) + "\n\n" docs = {} type.validstates.sort { |a,b| a.to_s <=> b.to_s }.reject { |sname| state = type.statebyname(sname) state.nodoc }.each { |sname| state = type.statebyname(sname) unless state raise "Could not retrieve state %s on type %s" % [sname, type.name] end doc = nil str = nil unless doc = state.doc $stderr.puts "No docs for %s[%s]" % [type, sname] next end doc = doc.dup str = doc str = scrub(str) #str = indent(str, $tab) docs[sname] = str } puts "\n### %s Parameters\n" % name.to_s.capitalize type.parameters.sort { |a,b| a.to_s <=> b.to_s }.each { |name,param| #docs[name] = indent(scrub(type.paramdoc(name)), $tab) docs[name] = scrub(type.paramdoc(name)) } docs.sort { |a, b| a[0].to_s <=> b[0].to_s }.each { |name, doc| namevar = type.namevar == name and name != :name paramwrap(name, doc, namevar) } puts "\n" } end send(mode) puts " ---------------- " puts "\n*This page autogenerated on %s*" % Time.now # $Id$