Refactoring puppetdoc so it is a bit cleaner and is actually object-oriented. PDF output still fails miserably (there has to be some kind of markup problem, but I have no idea what), but other output now successfully varies on the pages.

git-svn-id: https://reductivelabs.com/svn/puppet/trunk@2411 980ebf18-57e1-0310-9a29-db15c13687c0
This commit is contained in:
luke 2007-04-24 18:59:20 +00:00
Родитель 0ff37720f9
Коммит 0681cfa481
3 изменённых файлов: 262 добавлений и 207 удалений

Просмотреть файл

@ -8,7 +8,7 @@
#
# = Usage
#
# puppetdoc [-h|--help] [-m|--mode <typedocs|configref>
# puppetdoc [-a|--all] [-h|--help] [-m|--mode <text|pdf|trac> [-s|--section <[type]|configuration|report|function>]
#
# = Description
#
@ -26,19 +26,14 @@
# Print this help message
#
# mode::
# Print documentation of a given type. Valid optinos are 'typedocs', for
# resource type documentation, and 'configref', for documentation on all
# of the configuration parameters.
# Determine the output mode. Valid modes are 'text', 'trac', and 'pdf'. Note that 'trac' mode only works on Reductive Labs servers. The default mode is 'text'.
#
# pdf::
# Create a PDF of the output.
#
# trac::
# Write the reference docs to trac. Only works on servers at Reductive Labs.
# section::
# Handle a particular section. Available sections are 'type', 'configuration', 'report', and 'function'. The default section is 'type'.
#
# = Example
#
# $ puppetdoc > /tmp/reference.rst
# $ puppetdoc > /tmp/type_reference.rst
#
# = Author
#
@ -46,37 +41,194 @@
#
# = Copyright
#
# Copyright (c) 2005 Reductive Labs, LLC
# Copyright (c) 2005-2007 Reductive Labs, LLC
# Licensed under the GNU Public License
require 'puppet'
class PuppetDoc
include Puppet::Util::Docs
@@sections = {}
attr_accessor :page, :depth, :header, :title
def self.[](name)
@@sections[name]
end
def self.each
@@sections.sort { |a, b| a[0].to_s <=> b[0].to_s }.each { |name, instance| yield instance }
end
def self.footer
"\n\n----------------\n\n*This page autogenerated on %s*\n" % Time.now
end
def self.page(*sections)
depth = 4
# Use the minimum depth
sections.each do |name|
section = @@sections[name] or raise "Could not find section %s" % name
depth = section.depth if section.depth < depth
end
text = ".. contents:: :depth: 2\n\n"
end
def self.pdf(text)
puts "creating pdf"
File.open("/tmp/puppetdoc.txt", "w") do |f|
f.puts text
end
rst2latex = %x{which rst2latex}
if $? != 0 or rst2latex =~ /no /
rst2latex = %x{which rst2latex.py}
end
if $? != 0 or rst2latex =~ /no /
raise "Could not find rst2latex"
end
rst2latex.chomp!
cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex}
output = %x{#{cmd}}
unless $? == 0
$stderr.puts "rst2latex failed"
$stderr.puts output
exit(1)
end
$stderr.puts output
# Now convert to pdf
puts "handling pdf"
Dir.chdir("/tmp") do
%x{texi2pdf puppetdoc.tex >/dev/null 2>/dev/null}
end
#if FileTest.exists?("/tmp/puppetdoc.pdf")
# FileUtils.mv("/tmp/puppetdoc.pdf", "/export/apache/docroots/reductivelabs.com/htdocs/downloads/puppet/reference.pdf")
#end
end
def self.sections
@@sections.keys.sort { |a,b| a.to_s <=> b.to_s }
end
HEADER_LEVELS = [nil, "=", "-", "+", "'", "~"]
def h(name, level)
return "%s\n%s\n" % [name, HEADER_LEVELS[level] * name.to_s.length]
end
def initialize(name, options = {}, &block)
@name = name
options.each do |option, value|
send(option.to_s + "=", value)
end
meta_def(:generate, &block)
@@sections[name] = self
# Now handle the defaults
@title ||= "%s Reference" % @name.to_s.capitalize
@page ||= @title.gsub(/\s+/, '')
@depth ||= 2
@header ||= ""
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, options = {})
options[:level] ||= 5
#str = "%s : " % name
str = h(name, options[:level])
if options[:namevar]
str += "- **namevar**\n\n"
end
str += text
#str += text.gsub(/\n/, "\n ")
str += "\n\n"
return str
end
def output(withcontents = true)
# First the header
text = h(@title, 1)
if withcontents
text += ".. contents:: :depth: %s\n\n" % @depth
end
text += @header
text += generate()
if withcontents
text += self.class.footer
end
return text
end
def text
puts output
end
def trac
File.open("/tmp/puppetdoc.txt", "w") do |f|
f.puts "{{{
#!rst\n
#{self.output}
}}}"
end
puts "Writing %s reference to trac as %s" % [@name, @page]
cmd = %{sudo trac-admin /export/svn/trac/puppet wiki import %s /tmp/puppetdoc.txt} % self.page
output = %x{#{cmd}}
unless $? == 0
$stderr.puts "trac-admin failed"
$stderr.puts output
exit(1)
end
unless output =~ /^\s+/
$stderr.puts output
end
end
end
require 'puppet'
require 'puppet/network/handler'
require 'getoptlong'
result = GetoptLong.new(
[ "--pdf", "-p", GetoptLong::NO_ARGUMENT ],
[ "--all", "-a", GetoptLong::NO_ARGUMENT ],
[ "--trac", "-t", GetoptLong::NO_ARGUMENT ],
[ "--mode", "-m", GetoptLong::REQUIRED_ARGUMENT ],
[ "--section", "-s", GetoptLong::REQUIRED_ARGUMENT ],
[ "--help", "-h", GetoptLong::NO_ARGUMENT ]
)
debug = false
$tab = " "
options = {:modes => []}
options = {:sections => [], :mode => :text}
begin
result.each { |opt,arg|
case opt
when "--all"
options[:all] = true
when "--trac"
options[:trac] = true
when "--pdf"
options[:pdf] = true
when "--mode"
options[:modes] << arg.intern
case arg
when "text", "pdf", "trac":
options[:mode] = arg.intern
else
raise "Invalid output mode %s" % arg
end
when "--section"
options[:sections] << arg.intern
when "--help"
if Puppet.features.usage?
RDoc::usage && exit
@ -91,23 +243,52 @@ rescue GetoptLong::InvalidOption => detail
exit(1)
end
if options[:modes].empty?
options[:modes] << :typedocs
if options[:sections].empty?
options[:sections] << :type
end
include Puppet::Util::Docs
config = PuppetDoc.new :configuration, :depth => 1 do
docs = {}
Puppet.config.each do |name, object|
docs[name] = object
end
TRACMAP = {
:configref => "ConfigurationReference",
:reports => "ReportReference",
:functions => "FunctionReference",
:typedocs => "TypeReference"
}
str = ""
docs.sort { |a, b|
a[0].to_s <=> b[0].to_s
}.each do |name, object|
# Make each name an anchor
header = name.to_s
str += h(header, 3)
HEADERS = {
:configref => "Puppet Configuration Reference
==============================
# Print the doc string itself
begin
str += object.desc.gsub(/\n/, " ")
rescue => detail
puts detail.backtrace
puts detail
end
str += "\n\n"
# Now print the data about the item.
str += ""
val = object.default
if name.to_s == "vardir"
val = "/var/puppet"
elsif name.to_s == "confdir"
val = "/etc/puppet"
end
str += "- **Section**: %s\n" % object.section
unless val == ""
str += "- **Default**: %s\n" % val
end
str += "\n"
end
return str
end
config.header = "
Specifying Configuration Parameters
-----------------------------------
@ -181,24 +362,26 @@ and one `puppet` user) if it is invoked as `root` with the `--mkusers` argument:
Signals
-------
The `puppetd` and `puppetmasterd` executables catch some signals for special
handling. Both daemons catch (`SIGHUP`), which forces the server to restart
tself. Predictably, interrupt and terminate (`SIGINT` and `SIGHUP`) will shut
down the server, whether it be an instance of `puppetd` or `puppetmasterd`.
The ``puppetd`` and ``puppetmasterd`` executables catch some signals for special
handling. Both daemons catch (``SIGHUP``), which forces the server to restart
tself. Predictably, interrupt and terminate (``SIGINT`` and ``SIGHUP``) will shut
down the server, whether it be an instance of ``puppetd`` or ``puppetmasterd``.
Sending the `SIGUSR1` signal to an instance of `puppetd` will cause it to
Sending the ``SIGUSR1`` signal to an instance of ``puppetd`` will cause it to
immediately begin a new configuration transaction with the server. This
signal has no effect on `puppetmasterd`.
signal has no effect on ``puppetmasterd``.
Configuration Parameter Reference
---------------------------------
Below is a list of all documented parameters. Not all of them are valid with all
Puppet executables, but the executables will ignore any inappropriate values.
Below is a list of all documented parameters. Any default values are in ``block type`` at the end of the description.
"
",
:reports => "
Reports Reference
=================
report = PuppetDoc.new :report do
Puppet::Network::Handler.report.reportdocs
end
report.header = "
Puppet clients can report back to the server after each transaction. This
transaction report is sent as a YAML dump of the
``Puppet::Transaction::Report`` class and includes every log message that was
@ -214,11 +397,12 @@ reports must be comma-separated. You can also specify ``none`` to disable
reports entirely.
Puppet provides multiple report handlers that will process client reports:
"
",
:functions => "
Function Reference
==================
function = PuppetDoc.new :function do
Puppet::Parser::Functions.functiondocs
end
function.header = "
There are two types of functions in Puppet: Statements and rvalues.
Statements stand on their own and do not return arguments; they are used for
performing stand-alone work like importing. Rvalues return values and can
@ -226,102 +410,9 @@ only be used in a statement requiring a value, such as an assignment or a case
statement.
Here are the functions available in Puppet:
",
:typedocs => "
Resource Type Reference
=======================
"
}
def h(name, level)
levels = [nil, "=", "-", "+", "'", "~"]
return "%s\n%s\n" % [name, levels[level] * name.to_s.length]
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, options = {})
options[:level] ||= 5
#str = "%s : " % name
str = h(name, options[:level])
if options[:namevar]
str += "- **namevar**\n\n"
end
str += text
#str += text.gsub(/\n/, "\n ")
str += "\n\n"
return str
end
def tracwrite(text, mode)
File.open("/tmp/puppetdoc.txt", "w") do |f|
f.puts "{{{
#!rst\n
#{text}
}}}"
end
cmd = %{sudo trac-admin /export/svn/trac/puppet wiki import %s /tmp/puppetdoc.txt} % TRACMAP[mode]
output = %x{#{cmd}}
unless $? == 0
$stderr.puts "trac-admin failed"
$stderr.puts output
exit(1)
end
unless output =~ /^\s+/
$stderr.puts output
end
end
# Print the docs for arguments
def self.configref
docs = {}
Puppet.config.each do |name, object|
docs[name] = object
end
str = ""
docs.sort { |a, b|
a[0].to_s <=> b[0].to_s
}.each do |name, object|
# Make each name an anchor
header = name.to_s
str += h(header, 3)
# Print the doc string itself
begin
str += object.desc.gsub(/\n/, " ")
rescue => detail
puts detail.backtrace
puts detail
end
str += "\n"
# Now print the data about the item.
str += ""
default = ""
val = object.value
str += "- **Section**: %s\n" % object.section
unless val == ""
str += "- **Default**: %s\n" % val
end
#if val = object.value and val != ""
# default = " ``%s``" % val
#end
str += "\n"
end
return str
end
# Print the docs for types
def self.typedocs
type = PuppetDoc.new :type do
types = {}
Puppet::Type.loadall
@ -474,78 +565,38 @@ Resource Types
str
end
def self.reports
Puppet::Network::Handler.report.reportdocs
end
def self.functions
Puppet::Parser::Functions.functiondocs
end
if options[:all]
options[:modes] = HEADERS.keys
options[:sections] = PuppetDoc.sections
end
text = ".. contents::\n\n"
options[:modes].sort { |a, b| a.to_s <=> b.to_s }.each do |mode|
unless respond_to?(mode)
raise "Invalid mode %s" % mode
case options[:mode]
when :trac
options[:sections].each do |name|
section = PuppetDoc[name] or raise "Could not find section %s" % name
unless options[:mode] == :pdf
section.trac
end
end
text += HEADERS[mode]
text += send(mode)
end
text += "
----------------
"
text += "\n*This page autogenerated on %s*" % Time.now
if options[:trac]
if options[:modes].length > 1
raise "Cannot write more than one mode to trac at once"
end
tracwrite(text, options[:modes][0])
else
text = ".. contents:: :depth: 1\n\n"
options[:sections].sort { |a,b| a.to_s <=> b.to_s }.each do |name|
section = PuppetDoc[name]
# Add the per-section text, but with no ToC
text += section.output(false)
end
text += PuppetDoc.footer
# Replace the trac links, since they're invalid everywhere else
text.gsub!(/`\w+\s+([^`]+)`:trac/) { |m| $1 }
text.gsub!(/`\w+\s+([^`]+)`:trac:/) { |m| $1 }
if options[:pdf]
File.open("/tmp/puppetdoc.txt", "w") do |f|
f.puts text
end
rst2latex = %x{which rst2latex}
if $? != 0 or rst2latex =~ /no /
rst2latex = %x{which rst2latex.py}
end
if $? != 0 or rst2latex =~ /no /
raise "Could not find rst2latex"
end
rst2latex.chomp!
cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex}
output = %x{#{cmd}}
unless $? == 0
$stderr.puts "trac-admin failed"
$stderr.puts output
exit(1)
end
$stderr.puts output
# Now convert to pdf
puts "handling pdf"
Dir.chdir("/tmp") do
%x{texi2pdf puppetdoc.tex >/dev/null 2>/dev/null}
end
if FileTest.exists?("/tmp/puppetdoc.pdf")
FileUtils.mv("/tmp/puppetdoc.pdf", "/export/apache/docroots/reductivelabs.com/htdocs/downloads/puppet/reference.pdf")
end
if options[:mode] == :pdf
PuppetDoc.pdf(text)
else
puts text
end
end
# $Id$

Просмотреть файл

@ -15,8 +15,10 @@ module Puppet
end
self.setdefaults(:puppet,
:confdir => [conf, "The main Puppet configuration directory."],
:vardir => [var, "Where Puppet stores dynamic and growing data."],
:confdir => [conf, "The main Puppet configuration directory. The default for this parameter is calculated based on the user. If the process
is runnig as root or the user that ``puppetmasterd`` is supposed to run as, it defaults to a system directory, but if it's running as any other user,
it defaults to being in ``~``."],
:vardir => [var, "Where Puppet stores dynamic and growing data. The default for this parameter is calculated specially, like `confdir`_."],
:name => [name, "The name of the service, if we are running as one. The
default is essentially $0 without the path or ``.rb``."]
)

Просмотреть файл

@ -1,13 +1,15 @@
# Provides feature definitions.
require 'puppet/util/methodhelper'
require 'puppet/util/docs'
require 'puppet/util'
module Puppet::Util::ProviderFeatures
include Puppet::Util::Docs
# The class that models the features and handles checking whether the features
# are present.
class ProviderFeature
require 'puppet/util/methodhelper'
require 'puppet/util/docs'
require 'puppet/util'
include Puppet::Util
include Puppet::Util::MethodHelper
include Puppet::Util::Docs
attr_accessor :name, :docs, :methods
# Are all of the requirements met?