diff --git a/lib/puppet/application/doc.rb b/lib/puppet/application/doc.rb index 1f6c63286..aaefd6e75 100644 --- a/lib/puppet/application/doc.rb +++ b/lib/puppet/application/doc.rb @@ -1,181 +1,178 @@ require 'puppet/application' class Puppet::Application::Doc < Puppet::Application should_not_parse_config run_mode :master attr_accessor :unknown_args, :manifest def preinit - {:references => [], :mode => :text, :format => :to_rest }.each do |name,value| + {:references => [], :mode => :text, :format => :to_markdown }.each do |name,value| options[name] = value end @unknown_args = [] @manifest = false end option("--all","-a") option("--outputdir OUTPUTDIR","-o") option("--verbose","-v") option("--debug","-d") option("--charset CHARSET") option("--format FORMAT", "-f") do |arg| method = "to_#{arg}" require 'puppet/util/reference' if Puppet::Util::Reference.method_defined?(method) options[:format] = method else raise "Invalid output format #{arg}" end end option("--mode MODE", "-m") do |arg| require 'puppet/util/reference' if Puppet::Util::Reference.modes.include?(arg) or arg.intern==:rdoc options[:mode] = arg.intern else raise "Invalid output mode #{arg}" end end option("--list", "-l") do |arg| require 'puppet/util/reference' puts Puppet::Util::Reference.references.collect { |r| Puppet::Util::Reference.reference(r).doc }.join("\n") exit(0) end option("--reference REFERENCE", "-r") do |arg| options[:references] << arg.intern end def handle_unknown( opt, arg ) @unknown_args << {:opt => opt, :arg => arg } true end def run_command return[:rdoc].include?(options[:mode]) ? send(options[:mode]) : other end def rdoc exit_code = 0 files = [] unless @manifest env = Puppet::Node::Environment.new files += env.modulepath files << File.dirname(env[:manifest]) end files += command_line.args Puppet.info "scanning: #{files.inspect}" Puppet.settings.setdefaults( "puppetdoc", "document_all" => [false, "Document all resources"] ) Puppet.settings[:document_all] = options[:all] || false begin require 'puppet/util/rdoc' if @manifest Puppet::Util::RDoc.manifestdoc(files) else options[:outputdir] = "doc" unless options[:outputdir] Puppet::Util::RDoc.rdoc(options[:outputdir], files, options[:charset]) end rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts "Could not generate documentation: #{detail}" exit_code = 1 end exit exit_code end def other text = "" with_contents = options[:references].length <= 1 exit_code = 0 require 'puppet/util/reference' options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name| raise "Could not find reference #{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 #{name}: #{detail}" exit_code = 1 next end end text += Puppet::Util::Reference.footer unless with_contents # We've only got one reference - # 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 def setup # sole manifest documentation if command_line.args.size > 0 options[:mode] = :rdoc @manifest = true end if options[:mode] == :rdoc setup_rdoc else setup_reference end end def setup_reference if options[:all] # Don't add dynamic references to the "all" list. require 'puppet/util/reference' options[:references] = Puppet::Util::Reference.references.reject do |ref| Puppet::Util::Reference.reference(ref).dynamic? end end options[:references] << :type if options[:references].empty? end def setup_rdoc(dummy_argument=:work_arround_for_ruby_GC_bug) # consume the unknown options # and feed them as settings if @unknown_args.size > 0 @unknown_args.each do |option| # force absolute path for modulepath when passed on commandline if option[:opt]=="--modulepath" or option[:opt] == "--manifestdir" option[:arg] = option[:arg].split(':').collect { |p| File.expand_path(p) }.join(':') end Puppet.settings.handlearg(option[:opt], option[:arg]) end end # Now parse the config Puppet.parse_config # Handle the logging settings. if options[:debug] or options[:verbose] if options[:debug] Puppet::Util::Log.level = :debug else Puppet::Util::Log.level = :info end Puppet::Util::Log.newdestination(:console) end end end diff --git a/lib/puppet/util/command_line/puppetdoc b/lib/puppet/util/command_line/puppetdoc index 8f24ea5ef..45a9c6518 100755 --- a/lib/puppet/util/command_line/puppetdoc +++ b/lib/puppet/util/command_line/puppetdoc @@ -1,67 +1,67 @@ #!/usr/bin/env ruby # # = Synopsis # # Generate a reference for all Puppet types. Largely meant for internal Puppet # Labs use. # # = Usage # # puppet doc [-a|--all] [-h|--help] [-o|--outputdir ] [-m|--mode ] # [-r|--reference <[type]|configuration|..>] [--charset CHARSET] [manifest-file] # # = Description # # If mode is not 'rdoc', then this command generates a Markdown 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 Puppet Labs web site. # # In 'rdoc' mode, this command generates an html RDoc hierarchy describing the manifests that # are in 'manifestdir' and 'modulepath' configuration directives. # The generated documentation directory is doc by default but can be changed with the 'outputdir' option. # # If the command is started with 'manifest-file' command-line arguments, puppet doc generate a single # manifest documentation that is output on stdout. # # = Options # # all:: # Output the docs for all of the reference types. In 'rdoc' modes, this also outputs documentation for all resources # # help:: # Print this help message # # outputdir:: # Specifies the directory where to output the rdoc documentation in 'rdoc' mode. # # mode:: -# Determine the output mode. Valid modes are 'text', 'trac', 'pdf' and 'rdoc'. The 'pdf' mode creates PDF formatted files in the /tmp directory. The default mode is 'text'. In 'rdoc' mode you must provide 'manifests-path' +# Determine the output mode. Valid modes are 'text', 'pdf' and 'rdoc'. The 'pdf' mode creates PDF formatted files in the /tmp directory. The default mode is 'text'. In 'rdoc' mode you must provide 'manifests-path' # # reference:: # Build a particular reference. Get a list of references by running +puppet doc --list+. # # charset:: # Used only in 'rdoc' mode. It sets the charset used in the html files produced. # # = Example # -# $ puppet doc -r type > /tmp/type_reference.rst +# $ puppet doc -r type > /tmp/type_reference.markdown # or # $ puppet doc --outputdir /tmp/rdoc --mode rdoc /path/to/manifests # or # $ puppet doc /etc/puppet/manifests/site.pp # or # $ puppet doc -m pdf -r configuration # # = Author # # Luke Kanies # # = Copyright # # Copyright (c) 2005-2007 Puppet Labs, LLC # Licensed under the GNU Public License #Puppet::Application[:doc].run diff --git a/lib/puppet/util/reference.rb b/lib/puppet/util/reference.rb index 95efeb1c1..a4921ed2a 100644 --- a/lib/puppet/util/reference.rb +++ b/lib/puppet/util/reference.rb @@ -1,149 +1,140 @@ require 'puppet/util/instance_loader' require 'fileutils' # Manage Reference Documentation. class Puppet::Util::Reference include Puppet::Util include Puppet::Util::Docs extend Puppet::Util::InstanceLoader instance_load(:reference, 'puppet/reference') def self.footer "\n\n----------------\n\n*This page autogenerated on #{Time.now}*\n" end def self.modes %w{pdf text} end def self.newreference(name, options = {}, &block) ref = self.new(name, options, &block) instance_hash(:reference)[symbolize(name)] = ref ref end def self.page(*sections) depth = 4 # Use the minimum depth sections.each do |name| section = reference(name) or raise "Could not find section #{name}" depth = section.depth if section.depth < depth end end def self.pdf(text) puts "creating pdf" Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f| f.puts text end rst2latex = which('rst2latex') || which('rst2latex.py') || raise("Could not find rst2latex") cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex} Puppet::Util.secure_open("/tmp/puppetdoc.tex","w") do |f| # If we get here without an error, /tmp/puppetdoc.tex isn't a tricky cracker's symlink end output = %x{#{cmd}} unless $CHILD_STATUS == 0 $stderr.puts "rst2latex failed" $stderr.puts output exit(1) end $stderr.puts output # Now convert to pdf Dir.chdir("/tmp") do %x{texi2pdf puppetdoc.tex >/dev/null 2>/dev/null} end end def self.references instance_loader(:reference).loadall loaded_instances(:reference).sort { |a,b| a.to_s <=> b.to_s } end HEADER_LEVELS = [nil, "#", "##", "###", "####", "#####"] attr_accessor :page, :depth, :header, :title, :dynamic attr_writer :doc def doc if defined?(@doc) return "#{@name} - #{@doc}" else return @title end end def dynamic? self.dynamic end def h(name, level) "#{HEADER_LEVELS[level]} #{name}\n\n" end def initialize(name, options = {}, &block) @name = name options.each do |option, value| send(option.to_s + "=", value) end meta_def(:generate, &block) # Now handle the defaults @title ||= "#{@name.to_s.capitalize} Reference" @page ||= @title.gsub(/\s+/, '') @depth ||= 2 @header ||= "" end # Indent every line in the chunk except those which begin with '..'. def indent(text, tab) text.gsub(/(^|\A)/, tab).gsub(/^ +\.\./, "..") end def option(name, value) ":#{name.to_s.capitalize}: #{value}\n" end def paramwrap(name, text, options = {}) options[:level] ||= 5 #str = "#{name} : " str = h(name, options[:level]) str += "- **namevar**\n\n" if options[:namevar] str += text #str += text.gsub(/\n/, "\n ") str += "\n\n" end - # Remove all trac links. - def strip_trac(text) - text.gsub(/`\w+\s+([^`]+)`:trac:/) { |m| $1 } - end - def text puts output end - def to_rest(withcontents = true) + def to_markdown(withcontents = true) # First the header text = h(@title, 1) text += "\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on #{Time.now.to_s})*\n\n" text += @header text += generate text += self.class.footer if withcontents text end - - def to_text(withcontents = true) - strip_trac(to_rest(withcontents)) - end end diff --git a/spec/integration/reference/providers_spec.rb b/spec/integration/reference/providers_spec.rb index 8b95ca118..c2b1e17c5 100755 --- a/spec/integration/reference/providers_spec.rb +++ b/spec/integration/reference/providers_spec.rb @@ -1,17 +1,17 @@ #!/usr/bin/env ruby Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } require 'puppet/util/reference' reference = Puppet::Util::Reference.reference(:providers) describe reference do it "should exist" do reference.should_not be_nil end - it "should be able to be rendered as text" do - lambda { reference.to_text }.should_not raise_error + it "should be able to be rendered as markdown" do + lambda { reference.to_markdown }.should_not raise_error end end diff --git a/spec/unit/application/doc_spec.rb b/spec/unit/application/doc_spec.rb index 55da5e39a..ed723636b 100755 --- a/spec/unit/application/doc_spec.rb +++ b/spec/unit/application/doc_spec.rb @@ -1,349 +1,349 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/doc' require 'puppet/util/reference' require 'puppet/util/rdoc' describe Puppet::Application::Doc do before :each do @doc = Puppet::Application[:doc] @doc.stubs(:puts) @doc.preinit Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) end it "should ask Puppet::Application to not parse Puppet configuration file" do @doc.should_parse_config?.should be_false end it "should declare a other command" do @doc.should respond_to(:other) end it "should declare a rdoc command" do @doc.should respond_to(:rdoc) end it "should declare a fallback for unknown options" do @doc.should respond_to(:handle_unknown) end it "should declare a preinit block" do @doc.should respond_to(:preinit) end describe "in preinit" do it "should set references to []" do @doc.preinit @doc.options[:references].should == [] end it "should init mode to text" do @doc.preinit @doc.options[:mode].should == :text end - it "should init format to to_rest" do + it "should init format to to_markdown" do @doc.preinit - @doc.options[:format].should == :to_rest + @doc.options[:format].should == :to_markdown end end describe "when handling options" do [:all, :outputdir, :verbose, :debug, :charset].each do |option| it "should declare handle_#{option} method" do @doc.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @doc.options.expects(:[]=).with(option, 'arg') @doc.send("handle_#{option}".to_sym, 'arg') end end it "should store the format if valid" do Puppet::Util::Reference.stubs(:method_defined?).with('to_format').returns(true) @doc.options.expects(:[]=).with(:format, 'to_format') @doc.handle_format('format') end it "should raise an error if the format is not valid" do Puppet::Util::Reference.stubs(:method_defined?).with('to_format').returns(false) lambda { @doc.handle_format('format') } end it "should store the mode if valid" do Puppet::Util::Reference.stubs(:modes).returns(stub('mode', :include? => true)) @doc.options.expects(:[]=).with(:mode, :mode) @doc.handle_mode('mode') end it "should store the mode if :rdoc" do Puppet::Util::Reference.modes.stubs(:include?).with('rdoc').returns(false) @doc.options.expects(:[]=).with(:mode, :rdoc) @doc.handle_mode('rdoc') end it "should raise an error if the mode is not valid" do Puppet::Util::Reference.modes.stubs(:include?).with('unknown').returns(false) lambda { @doc.handle_mode('unknown') } end it "should list all references on list and exit" do reference = stubs 'reference' ref = stubs 'ref' Puppet::Util::Reference.stubs(:references).returns([reference]) Puppet::Util::Reference.expects(:reference).with(reference).returns(ref) ref.expects(:doc) @doc.expects(:exit) @doc.handle_list(nil) end it "should add reference to references list with --reference" do @doc.options[:references] = [:ref1] @doc.handle_reference('ref2') @doc.options[:references].should == [:ref1,:ref2] end end describe "during setup" do before :each do Puppet::Log.stubs(:newdestination) @doc.command_line.stubs(:args).returns([]) end it "should default to rdoc mode if there are command line arguments" do @doc.command_line.stubs(:args).returns(["1"]) @doc.stubs(:setup_rdoc) @doc.options.expects(:[]=).with(:mode,:rdoc) @doc.setup end it "should call setup_rdoc in rdoc mode" do @doc.options.stubs(:[]).with(:mode).returns(:rdoc) @doc.expects(:setup_rdoc) @doc.setup end it "should call setup_reference if not rdoc" do @doc.options.stubs(:[]).with(:mode).returns(:test) @doc.expects(:setup_reference) @doc.setup end describe "in non-rdoc mode" do it "should get all non-dynamic reference if --all" do @doc.options.stubs(:[]).with(:all).returns(true) @doc.options.stubs(:[]).with(:references).returns([]) static = stub 'static', :dynamic? => false dynamic = stub 'dynamic', :dynamic? => true Puppet::Util::Reference.stubs(:reference).with(:static).returns(static) Puppet::Util::Reference.stubs(:reference).with(:dynamic).returns(dynamic) Puppet::Util::Reference.stubs(:references).returns([:static,:dynamic]) @doc.options.stubs(:[]=).with(:references, [:static]) @doc.setup_reference end it "should default to :type if no references" do @doc.options.stubs(:[]).with(:all).returns(false) array = stub 'array', :empty? => true @doc.options.stubs(:[]).with(:references).returns(array) array.expects(:<<).with(:type) @doc.setup_reference end end describe "in rdoc mode" do before :each do @doc.options.stubs(:[]).returns(false) Puppet.stubs(:parse_config) Puppet::Util::Log.stubs(:level=) Puppet::Util::Log.stubs(:newdestination) end describe "when there are unknown args" do it "should expand --modulepath if any" do @doc.unknown_args = [ { :opt => "--modulepath", :arg => "path" } ] Puppet.settings.stubs(:handlearg) File.expects(:expand_path).with("path") @doc.setup_rdoc end it "should expand --manifestdir if any" do @doc.unknown_args = [ { :opt => "--manifestdir", :arg => "path" } ] Puppet.settings.stubs(:handlearg) File.expects(:expand_path).with("path") @doc.setup_rdoc end it "should give them to Puppet.settings" do @doc.unknown_args = [ { :opt => :option, :arg => :argument } ] Puppet.settings.expects(:handlearg).with(:option,:argument) @doc.setup_rdoc end end it "should operate in master run_mode" do @doc.class.run_mode.name.should == :master @doc.setup_rdoc end it "should parse puppet configuration" do Puppet.expects(:parse_config) @doc.setup_rdoc end it "should set log level to debug if --debug" do @doc.options.stubs(:[]).with(:debug).returns(true) Puppet::Util::Log.expects(:level=).with(:debug) @doc.setup_rdoc end it "should set log level to info if --verbose" do @doc.options.stubs(:[]).with(:verbose).returns(true) Puppet::Util::Log.expects(:level=).with(:info) @doc.setup_rdoc end it "should set log destination to console if --verbose" do @doc.options.stubs(:[]).with(:verbose).returns(true) Puppet::Util::Log.expects(:newdestination).with(:console) @doc.setup_rdoc end it "should set log destination to console if --debug" do @doc.options.stubs(:[]).with(:debug).returns(true) Puppet::Util::Log.expects(:newdestination).with(:console) @doc.setup_rdoc end end end describe "when running" do describe "in rdoc mode" do before :each do @doc.manifest = false Puppet.stubs(:info) Puppet.stubs(:[]).with(:trace).returns(false) @env = stub 'env' Puppet::Node::Environment.stubs(:new).returns(@env) @env.stubs(:modulepath).returns(['modules']) @env.stubs(:[]).with(:manifest).returns('manifests/site.pp') Puppet.stubs(:[]).with(:modulepath).returns('modules') Puppet.stubs(:[]).with(:manifestdir).returns('manifests') @doc.options.stubs(:[]).with(:all).returns(false) @doc.options.stubs(:[]).with(:outputdir).returns('doc') @doc.options.stubs(:[]).with(:charset).returns(nil) Puppet.settings.stubs(:[]=).with(:document_all, false) Puppet.settings.stubs(:setdefaults) Puppet::Util::RDoc.stubs(:rdoc) @doc.stubs(:exit) File.stubs(:expand_path).with('modules').returns('modules') File.stubs(:expand_path).with('manifests').returns('manifests') @doc.command_line.stubs(:args).returns([]) end it "should set document_all on --all" do @doc.options.expects(:[]).with(:all).returns(true) Puppet.settings.expects(:[]=).with(:document_all, true) @doc.rdoc end it "should call Puppet::Util::RDoc.rdoc in full mode" do Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests'], nil) @doc.rdoc end it "should call Puppet::Util::RDoc.rdoc with a charset if --charset has been provided" do @doc.options.expects(:[]).with(:charset).returns("utf-8") Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests'], "utf-8") @doc.rdoc end it "should call Puppet::Util::RDoc.rdoc in full mode with outputdir set to doc if no --outputdir" do @doc.options.expects(:[]).with(:outputdir).returns(false) Puppet::Util::RDoc.expects(:rdoc).with('doc', ['modules','manifests'], nil) @doc.rdoc end it "should call Puppet::Util::RDoc.manifestdoc in manifest mode" do @doc.manifest = true Puppet::Util::RDoc.expects(:manifestdoc) @doc.rdoc end it "should get modulepath and manifestdir values from the environment" do @env.expects(:modulepath).returns(['envmodules1','envmodules2']) @env.expects(:[]).with(:manifest).returns('envmanifests/site.pp') Puppet::Util::RDoc.expects(:rdoc).with('doc', ['envmodules1','envmodules2','envmanifests'], nil) @doc.rdoc end end describe "in the other modes" do it "should get reference in given format" do reference = stub 'reference' @doc.options.stubs(:[]).with(:mode).returns(:none) @doc.options.stubs(:[]).with(:references).returns([:ref]) require 'puppet/util/reference' Puppet::Util::Reference.expects(:reference).with(:ref).returns(reference) @doc.options.stubs(:[]).with(:format).returns(:format) @doc.stubs(:exit) reference.expects(:send).with { |format,contents| format == :format }.returns('doc') @doc.other end end end end