mirror of
https://github.com/elastic/logstash.git
synced 2025-04-21 13:18:16 -04:00
188 lines
4.9 KiB
Ruby
188 lines
4.9 KiB
Ruby
require "rubygems"
|
|
require "erb"
|
|
require "optparse"
|
|
require "bluecloth" # for markdown parsing
|
|
|
|
# TODO(sissel): Currently this doc generator doesn't follow ancestry, so
|
|
# LogStash::Input::Amqp inherits Base, but we don't parse the base file.
|
|
# We need this, though.
|
|
#
|
|
# TODO(sissel): Convert this to use ERB, not random bits of 'puts'
|
|
|
|
$: << Dir.pwd
|
|
$: << File.join(File.dirname(__FILE__), "..", "lib")
|
|
|
|
class LogStashConfigDocGenerator
|
|
COMMENT_RE = /^ *#(?: (.*)| *$)/
|
|
|
|
def initialize
|
|
@rules = {
|
|
COMMENT_RE => lambda { |m| add_comment(m[1]) },
|
|
/^ *class.*< *LogStash::(Outputs|Filters|Inputs)::Base/ => \
|
|
lambda { |m| set_class_description },
|
|
/^ *config .*/ => lambda { |m| add_config(m[0]) },
|
|
/^ *config_name .*/ => lambda { |m| set_config_name(m[0]) },
|
|
/^ *flag[( ].*/ => lambda { |m| add_flag(m[0]) },
|
|
/^ *(class|def|module) / => lambda { |m| clear_comments },
|
|
}
|
|
@comments = []
|
|
@settings = {}
|
|
@flags = {}
|
|
end
|
|
|
|
def parse(string)
|
|
buffer = ""
|
|
string.split("\n").each do |line|
|
|
# Join long lines
|
|
if line =~ COMMENT_RE
|
|
# nothing
|
|
else
|
|
# Join extended lines
|
|
if line =~ /(, *$)|(\\$)/
|
|
buffer += line.gsub(/\\$/, "")
|
|
next
|
|
end
|
|
end
|
|
|
|
line = buffer + line
|
|
buffer = ""
|
|
|
|
@rules.each do |re, action|
|
|
m = re.match(line)
|
|
if m
|
|
action.call(m)
|
|
end
|
|
end # RULES.each
|
|
end # string.split("\n").each
|
|
end # def parse
|
|
|
|
def set_class_description
|
|
@class_description = @comments.join("\n")
|
|
clear_comments
|
|
end # def set_class_description
|
|
|
|
def add_comment(comment)
|
|
@comments << comment
|
|
end # def add_comment
|
|
|
|
def add_config(code)
|
|
# call the code, which calls 'config' in this class.
|
|
# This will let us align comments with config options.
|
|
name, opts = eval(code)
|
|
|
|
description = BlueCloth.new(@comments.join("\n")).to_html
|
|
@settings[name] = opts.merge(:description => description)
|
|
clear_comments
|
|
end # def add_config
|
|
|
|
def add_flag(code)
|
|
# call the code, which calls 'config' in this class.
|
|
# This will let us align comments with config options.
|
|
p :code => code
|
|
fixed_code = code.gsub(/ do .*/, "")
|
|
p :fixedcode => fixed_code
|
|
name, description = eval(fixed_code)
|
|
@flags[name] = description
|
|
clear_comments
|
|
end # def add_config
|
|
|
|
def set_config_name(code)
|
|
name = eval(code)
|
|
@name = name
|
|
end # def set_config_name
|
|
|
|
# pretend to be the config DSL and just get the name
|
|
def config(name, opts={})
|
|
return name, opts
|
|
end # def config
|
|
|
|
# Pretend to support the flag DSL
|
|
def flag(*args, &block)
|
|
name = args.first
|
|
description = args.last
|
|
return name, description
|
|
end # def config
|
|
|
|
# pretend to be the config dsl's 'config_name' method
|
|
def config_name(name)
|
|
return name
|
|
end # def config_name
|
|
|
|
def clear_comments
|
|
@comments.clear
|
|
end # def clear_comments
|
|
|
|
def generate(file, settings)
|
|
require "logstash/inputs/base"
|
|
require "logstash/filters/base"
|
|
require "logstash/outputs/base"
|
|
require file
|
|
|
|
@comments = []
|
|
@settings = {}
|
|
@class_description = ""
|
|
|
|
# parse base first
|
|
parse(File.new(File.join(File.dirname(file), "base.rb"), "r").read)
|
|
|
|
# Now parse the real library
|
|
code = File.new(file).read
|
|
parse(code)
|
|
|
|
puts "Generating docs for #{file}"
|
|
|
|
if @name.nil?
|
|
$stderr.puts "Missing 'config_name' setting in #{file}?"
|
|
return nil
|
|
end
|
|
|
|
klass = LogStash::Config::Registry.registry[@name]
|
|
if klass.ancestors.include?(LogStash::Inputs::Base)
|
|
section = "input"
|
|
elsif klass.ancestors.include?(LogStash::Filters::Base)
|
|
section = "filter"
|
|
elsif klass.ancestors.include?(LogStash::Outputs::Base)
|
|
section = "output"
|
|
end
|
|
|
|
template_file = File.join(File.dirname(__FILE__), "docs.html.erb")
|
|
template = ERB.new(File.new(template_file).read, nil, "-")
|
|
|
|
# descriptions are assumed to be markdown
|
|
description = BlueCloth.new(@class_description).to_html
|
|
|
|
sorted_settings = @settings.sort { |a,b| a.first.to_s <=> b.first.to_s }
|
|
klassname = LogStash::Config::Registry.registry[@name].to_s
|
|
name = @name
|
|
|
|
if settings[:output]
|
|
dir = File.join(settings[:output], section + "s")
|
|
path = File.join(dir, "#{name}.html")
|
|
Dir.mkdir(settings[:output]) if !File.directory?(settings[:output])
|
|
Dir.mkdir(dir) if !File.directory?(dir)
|
|
File.open(path, "w") do |out|
|
|
out.puts(template.result(binding))
|
|
end
|
|
else
|
|
puts template.result(binding)
|
|
end
|
|
end # def generate
|
|
|
|
end # class LogStashConfigDocGenerator
|
|
|
|
if __FILE__ == $0
|
|
opts = OptionParser.new
|
|
settings = {}
|
|
opts.on("-o DIR", "--output DIR",
|
|
"Directory to output to; optional. If not specified,"\
|
|
"we write to stdout.") do |val|
|
|
settings[:output] = val
|
|
end
|
|
|
|
args = opts.parse(ARGV)
|
|
|
|
args.each do |arg|
|
|
gen = LogStashConfigDocGenerator.new
|
|
gen.generate(arg, settings)
|
|
end
|
|
end
|