#!/usr/bin/env ruby

#
# = Synopsis
#
# Generate a reference for all Puppet types.  Largely meant for internal Reductive
# Labs use.
#
# = Usage
#
#   puppetdoc [-a|--all] [-h|--help] [-m|--mode <text|pdf|trac> [-r|--reference <[type]|configuration|..>]
#
# = 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
#
# all::
#   Output the docs for all of the reference types.
#
# help::
#   Print this help message
#
# mode::
#   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'.
#
# reference::
#   Build a particular reference.  Get a list of references by running +puppetdoc --list+.
#
# = Example
#
#   $ puppetdoc -r type > /tmp/type_reference.rst
#
# = Author
#
# Luke Kanies
#
# = Copyright
#
# Copyright (c) 2005-2007 Reductive Labs, LLC
# Licensed under the GNU Public License

require 'puppet'
require 'puppet/util/reference'
require 'puppet/network/handler'
require 'getoptlong'

result = GetoptLong.new(
	[ "--all",	"-a",			GetoptLong::NO_ARGUMENT ],
	[ "--list",	"-l",			GetoptLong::NO_ARGUMENT ],
	[ "--format",	"-f",			GetoptLong::REQUIRED_ARGUMENT ],
	[ "--mode",	"-m",			GetoptLong::REQUIRED_ARGUMENT ],
	[ "--reference",	"-r",			GetoptLong::REQUIRED_ARGUMENT ],
	[ "--help",		"-h",			GetoptLong::NO_ARGUMENT ]
)

debug = false

$tab = "    "
options = {:references => [], :mode => :text, :format => :to_rest}

Reference = Puppet::Util::Reference

begin
    result.each { |opt,arg|
        case opt
        when "--all"
            options[:all] = true
        when "--format"
            method = "to_%s" % arg
            if Reference.method_defined?(method)
                options[:format] = method
            else
                raise "Invalid output format %s" % arg
            end
        when "--mode"
            if Reference.modes.include?(arg)
                options[:mode] = arg.intern
            else
                raise "Invalid output mode %s" % arg
            end
        when "--list"
            puts Reference.references.collect { |r| Reference.reference(r).doc }.join("\n")
            exit(0)
        when "--reference"
            options[:references] << arg.intern
        when "--help"
            if Puppet.features.usage?
                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'"
    exit(1)
end

if options[:all]
    # Don't add dynamic references to the "all" list.
    options[:references] = Reference.references.reject do |ref|
        Reference.reference(ref).dynamic?
    end
end

if options[:references].empty?
    options[:references] << :type
end

case options[:mode]
when :trac
    options[:references].each do |name|
        section = Puppet::Util::Reference.reference(name) or raise "Could not find section %s" % name
        unless options[:mode] == :pdf
            section.trac
        end
    end
else
    text = ""
    if options[:references].length > 1
        with_contents = false
    else
        with_contents = true
    end
    exit_code = 0
    options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name|
        raise "Could not find reference %s" % name unless section = Puppet::Util::Reference.reference(name)

        begin
            # Add the per-section text, but with no ToC
            text += section.send(options[:format], with_contents)
        rescue => detail
            puts detail.backtrace
            $stderr.puts "Could not generate reference %s: %s" % [name, detail]
            exit_code = 1
            next
        end
    end

    unless with_contents # We've only got one reference
        text += Puppet::Util::Reference.footer
    end

    # Replace the trac links, since they're invalid everywhere else
    text.gsub!(/`\w+\s+([^`]+)`:trac:/) { |m| $1 }

    if options[:mode] == :pdf
        Puppet::Util::Reference.pdf(text)
    else
        puts text
    end

    exit exit_code
end


