Skip to content

Commit 1dcc3e5

Browse files
committed
Refactor the parser to handle bulk parsing
puppet-strings can parse multiple files at once. This saves a lot of overhead of initializing Puppet over and over.
1 parent d30dc7a commit 1dcc3e5

1 file changed

Lines changed: 58 additions & 51 deletions

File tree

lib/kafo_parsers/puppet_strings_module_parser.rb

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,17 @@
77

88
module KafoParsers
99
class PuppetStringsModuleParser
10+
STRINGS_TYPE_MAP = {
11+
'hostclass' => 'puppet_classes',
12+
'definition' => 'defined_types',
13+
}
14+
1015
# You can call this method to get all supported information from a given manifest
1116
#
1217
# @param [ String ] manifest file path to parse
1318
# @return [ Hash ] hash containing values, validations, documentation, types, groups and conditions
1419
def self.parse(file)
15-
content = new(file)
16-
docs = content.docs
17-
18-
# data_type must be called before other validations
19-
data = {
20-
:object_type => content.data_type,
21-
:values => content.values,
22-
:validations => content.validations
23-
}
24-
data[:parameters] = data[:values].keys
25-
data.merge!(docs)
26-
data
20+
new([file]).by_file(file)
2721
end
2822

2923
def self.available?
@@ -35,11 +29,10 @@ def self.available?
3529
end
3630
end
3731

38-
def initialize(file)
39-
@file = file = File.expand_path(file)
40-
raise KafoParsers::ModuleName, "File not found #{file}, check your answer file" unless File.exist?(file)
32+
def initialize(paths)
33+
paths = paths.map { |path| File.expand_path(path) }
4134

42-
command = ['strings', 'generate', '--format', 'json', file]
35+
command = ['strings', 'generate', '--format', 'json'] + paths
4336
@raw_json, stderr, status = self.class.run_puppet(command)
4437

4538
unless status.success?
@@ -51,9 +44,20 @@ def initialize(file)
5144
rescue ::JSON::ParserError => e
5245
raise KafoParsers::ParseError, "'#{command}' returned invalid json output: #{e.message}\n#{@raw_json}"
5346
end
54-
self.data_type # we need to determine data_type before any further parsing
5547

56-
self
48+
if STRINGS_TYPE_MAP.values.all? { |key| @complete_hash[key].empty? }
49+
raise KafoParsers::ModuleName, "Nothing found in #{paths.join(',')}"
50+
end
51+
end
52+
53+
def by_file(file)
54+
data_type, parsed_hash = find_by_property('file', File.expand_path(file))
55+
format_result(data_type, parsed_hash)
56+
end
57+
58+
def by_name(name)
59+
data_type, parsed_hash = find_by_property('name', name)
60+
format_result(data_type, parsed_hash)
5761
end
5862

5963
# AIO and system default puppet bins are tested for existence, fallback to just `puppet` otherwise
@@ -67,29 +71,17 @@ def self.puppet_bin
6771
end
6872
end
6973

70-
def data_type
71-
@data_type ||= begin
72-
if (@parsed_hash = @complete_hash['puppet_classes'].find { |klass| klass['file'] == @file })
73-
'hostclass'
74-
elsif (@parsed_hash = @complete_hash['defined_types'].find { |klass| klass['file'] == @file })
75-
'definition'
76-
else
77-
raise KafoParsers::ParseError, "unable to find manifest data, syntax error in manifest #{@file}?"
78-
end
79-
end
80-
end
81-
82-
def values
83-
Hash[
84-
# combine known parameters (from tags) with any defaults provided
85-
tag_params.select { |param| !param['types'].nil? }.map { |param| [ param['name'], nil ] } +
86-
@parsed_hash.fetch('defaults', {}).map { |name, value| [ name, value.nil? ? nil : sanitize(value) ] }
87-
]
88-
end
74+
private
8975

90-
# unsupported in puppet strings parser
91-
def validations(param = nil)
92-
[]
76+
def format_result(data_type, parsed_hash)
77+
data = {
78+
:object_type => data_type,
79+
:values => values_for_parsed_hash(parsed_hash),
80+
:validations => [],
81+
}
82+
data[:parameters] = data[:values].keys
83+
data.merge!(docs_for_parsed_hash(parsed_hash))
84+
data
9385
end
9486

9587
# returns data in following form
@@ -99,25 +91,24 @@ def validations(param = nil)
9991
# :groups => { $param1 => ['Parameters', 'Advanced']},
10092
# :conditions => { $param1 => '$db_type == "mysql"'},
10193
# }
102-
def docs
94+
def docs_for_parsed_hash(parsed_hash)
10395
data = { :docs => {}, :types => {}, :groups => {}, :conditions => {} }
104-
if @parsed_hash.nil?
105-
raise KafoParsers::DocParseError, "no documentation found for manifest #{@file}, parsing error?"
106-
elsif !@parsed_hash['docstring'].nil? && !@parsed_hash['docstring']['text'].nil?
96+
97+
if parsed_hash.dig('docstring', 'text')
10798
# Lowest precedence: types given in the strings hash from class definition
108-
tag_params.each do |param|
99+
tag_params(parsed_hash).each do |param|
109100
data[:types][param['name']] = param['types'][0] unless param['types'].nil?
110101
end
111102

112103
# Next: types and other data from RDoc parser
113-
rdoc_parser = DocParser.new(@parsed_hash['docstring']['text']).parse
104+
rdoc_parser = DocParser.new(parsed_hash['docstring']['text']).parse
114105
data[:docs] = rdoc_parser.docs
115106
data[:groups] = rdoc_parser.groups
116107
data[:conditions] = rdoc_parser.conditions
117108
data[:types].merge! rdoc_parser.types
118109

119110
# Highest precedence: data in YARD @param stored in the 'text' field
120-
tag_params.each do |param|
111+
tag_params(parsed_hash).each do |param|
121112
param_name = param['name']
122113
unless param['text'].nil? || param['text'].empty?
123114
param_parser = ParamDocParser.new(param_name, param['text'].split($/))
@@ -131,7 +122,23 @@ def docs
131122
data
132123
end
133124

134-
private
125+
def values_for_parsed_hash(parsed_hash)
126+
Hash[
127+
# combine known parameters (from tags) with any defaults provided
128+
tag_params(parsed_hash).select { |param| !param['types'].nil? }.map { |param| [ param['name'], nil ] } +
129+
parsed_hash.fetch('defaults', {}).map { |name, value| [ name, value.nil? ? nil : sanitize(value) ] }
130+
]
131+
end
132+
133+
def find_by_property(property, value)
134+
STRINGS_TYPE_MAP.each do |data_type, key|
135+
if (parsed_hash = @complete_hash[key].find { |klass| klass[property] == value })
136+
return [data_type, parsed_hash]
137+
end
138+
end
139+
140+
raise KafoParsers::ParseError, "unable to find manifest data, syntax error in manifest #{file}?"
141+
end
135142

136143
def self.search_puppet_path(bin_name)
137144
# Find the location of the puppet executable and use that to
@@ -194,9 +201,9 @@ def sanitize(value)
194201
value
195202
end
196203

197-
def tag_params
198-
if @parsed_hash['docstring']['tags']
199-
@parsed_hash['docstring']['tags'].select { |tag| tag['tag_name'] == 'param' }
204+
def tag_params(parsed_hash)
205+
if parsed_hash['docstring']['tags']
206+
parsed_hash['docstring']['tags'].select { |tag| tag['tag_name'] == 'param' }
200207
else
201208
[]
202209
end

0 commit comments

Comments
 (0)