Skip to content

Commit 5bdcc4f

Browse files
authored
Merge pull request #162 from glennsarti/add-aggregate-metadata
(GH-163) Add aggregate metadata sidecar object and tasks
2 parents 482852b + 7e6ac3b commit 5bdcc4f

File tree

7 files changed

+261
-22
lines changed

7 files changed

+261
-22
lines changed

lib/puppet-languageserver-sidecar/puppet_helper_puppetstrings.rb

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,9 @@ def self.retrieve_via_puppet_strings(cache, options = {})
4747
object_types = options[:object_types].nil? ? available_documentation_types : options[:object_types]
4848
object_types.select! { |i| available_documentation_types.include?(i) }
4949

50-
result = {}
50+
result = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new
5151
return result if object_types.empty?
5252

53-
result[:classes] = PuppetLanguageServer::Sidecar::Protocol::PuppetClassList.new if object_types.include?(:class)
54-
result[:functions] = PuppetLanguageServer::Sidecar::Protocol::PuppetFunctionList.new if object_types.include?(:function)
55-
result[:types] = PuppetLanguageServer::Sidecar::Protocol::PuppetTypeList.new if object_types.include?(:type)
56-
5753
current_env = current_environment
5854
for_agent = options[:for_agent].nil? ? true : options[:for_agent]
5955
loaders = Puppet::Pops::Loaders.new(current_env, for_agent)
@@ -74,25 +70,25 @@ def self.retrieve_via_puppet_strings(cache, options = {})
7470
next if file_doc.nil?
7571

7672
if object_types.include?(:class) # rubocop:disable Style/IfUnlessModifier This reads better
77-
file_doc.classes.each { |item| result[:classes] << item }
73+
file_doc.classes.each { |item| result.append!(item) }
7874
end
7975
if object_types.include?(:function) # rubocop:disable Style/IfUnlessModifier This reads better
80-
file_doc.functions.each { |item| result[:functions] << item }
76+
file_doc.functions.each { |item| result.append!(item) }
8177
end
8278
if object_types.include?(:type)
8379
file_doc.types.each do |item|
84-
result[:types] << item unless name == 'whit' || name == 'component' # rubocop:disable Style/MultipleComparison
80+
result.append!(item) unless name == 'whit' || name == 'component' # rubocop:disable Style/MultipleComparison
8581
end
8682
end
8783
end
8884

8985
# Remove Puppet3 functions which have a Puppet4 function already loaded
9086
if object_types.include?(:function)
91-
pup4_functions = result[:functions].select { |i| i.function_version == 4 }.map { |i| i.key }
92-
result[:functions].reject! { |i| i.function_version == 3 && pup4_functions.include?(i.key) }
87+
pup4_functions = result.functions.select { |i| i.function_version == 4 }.map { |i| i.key }
88+
result.functions.reject! { |i| i.function_version == 3 && pup4_functions.include?(i.key) }
9389
end
9490

95-
result.each { |key, item| PuppetLanguageServerSidecar.log_message(:debug, "[PuppetHelper::retrieve_via_puppet_strings] Finished loading #{item.count} #{key}") }
91+
result.each_list { |key, item| PuppetLanguageServerSidecar.log_message(:debug, "[PuppetHelper::retrieve_via_puppet_strings] Finished loading #{item.count} #{key}") }
9692
result
9793
end
9894

lib/puppet-languageserver-sidecar/puppet_strings_helper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ class FileDocumentation
282282
attr_accessor :types
283283

284284
def initialize(path = nil)
285-
@path = path
285+
@path = path
286286
@classes = PuppetLanguageServer::Sidecar::Protocol::PuppetClassList.new
287287
@functions = PuppetLanguageServer::Sidecar::Protocol::PuppetFunctionList.new
288288
@types = PuppetLanguageServer::Sidecar::Protocol::PuppetTypeList.new

lib/puppet-languageserver/sidecar_protocol.rb

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,7 @@ def child_type
141141
end
142142
end
143143

144-
class NodeGraph
145-
include Base
146-
144+
class NodeGraph < BaseClass
147145
attr_accessor :dot_content
148146
attr_accessor :error_content
149147

@@ -337,7 +335,7 @@ def child_type
337335
end
338336
end
339337

340-
class Resource
338+
class Resource < BaseClass
341339
attr_accessor :manifest
342340

343341
def to_h
@@ -365,6 +363,83 @@ def child_type
365363
Resource
366364
end
367365
end
366+
367+
# This class is a little special as it contains a lot logic.
368+
# In essence this is just wrapping a hash with specific methods for the
369+
# the different types of metadata (classes, functions etc.)
370+
class AggregateMetadata < BaseClass
371+
def initialize
372+
super
373+
@aggregate = {}
374+
end
375+
376+
def classes
377+
@aggregate[:classes]
378+
end
379+
380+
def functions
381+
@aggregate[:functions]
382+
end
383+
384+
def types
385+
@aggregate[:types]
386+
end
387+
388+
def append!(obj)
389+
list_for_object_class(obj.class) << obj
390+
end
391+
392+
def to_json(*options)
393+
@aggregate.to_json(options)
394+
end
395+
396+
def from_json!(json_string)
397+
obj = JSON.parse(json_string)
398+
obj.each do |key, value|
399+
info = METADATA_LIST[key.intern]
400+
next if info.nil?
401+
list = list_for_object_class(info[:item_class])
402+
value.each { |i| list << info[:item_class].new.from_h!(i) }
403+
end
404+
self
405+
end
406+
407+
def each_list
408+
return unless block_given?
409+
@aggregate.each { |k, v| yield k, v }
410+
end
411+
412+
private
413+
414+
# When adding a new metadata item:
415+
# - Add to the information to this hash
416+
# - Add a method to access the aggregate
417+
METADATA_LIST = {
418+
:classes => {
419+
:item_class => PuppetClass,
420+
:list_class => PuppetClassList
421+
},
422+
:functions => {
423+
:item_class => PuppetFunction,
424+
:list_class => PuppetFunctionList
425+
},
426+
:types => {
427+
:item_class => PuppetType,
428+
:list_class => PuppetTypeList
429+
}
430+
}.freeze
431+
432+
def list_for_object_class(klass)
433+
METADATA_LIST.each do |name, info|
434+
if klass == info[:item_class]
435+
@aggregate[name] = info[:list_class].new if @aggregate[name].nil?
436+
return @aggregate[name]
437+
end
438+
end
439+
440+
raise "Unknown object class #{klass.name}"
441+
end
442+
end
368443
end
369444
end
370445
end

lib/puppet_languageserver_sidecar.rb

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,13 @@ def self.require_gems(options)
105105

106106
ACTION_LIST = %w[
107107
noop
108+
default_aggregate
108109
default_classes
109110
default_functions
110111
default_types
111112
node_graph
112113
resource_list
114+
workspace_aggregate
113115
workspace_classes
114116
workspace_functions
115117
workspace_types
@@ -258,26 +260,35 @@ def self.execute(options)
258260
when 'noop'
259261
[]
260262

263+
when 'default_aggregate'
264+
cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
265+
if use_puppet_strings
266+
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => PuppetLanguageServerSidecar::PuppetHelper.available_documentation_types)
267+
else
268+
log_message(:warn, 'The default_aggregate action is only supported with the puppetstrings feature flag')
269+
{}
270+
end
271+
261272
when 'default_classes'
262273
cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
263274
if use_puppet_strings
264-
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => [:class])[:classes]
275+
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => [:class]).classes
265276
else
266277
PuppetLanguageServerSidecar::PuppetHelper.retrieve_classes(cache)
267278
end
268279

269280
when 'default_functions'
270281
cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
271282
if use_puppet_strings
272-
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => [:function])[:functions]
283+
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => [:function]).functions
273284
else
274285
PuppetLanguageServerSidecar::PuppetHelper.retrieve_functions(cache)
275286
end
276287

277288
when 'default_types'
278289
cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
279290
if use_puppet_strings
280-
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => [:type])[:types]
291+
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => [:type]).types
281292
else
282293
PuppetLanguageServerSidecar::PuppetHelper.retrieve_types(cache)
283294
end
@@ -307,14 +318,26 @@ def self.execute(options)
307318
end
308319
PuppetLanguageServerSidecar::PuppetHelper.get_puppet_resource(typename, title)
309320

321+
when 'workspace_aggregate'
322+
return nil unless inject_workspace_as_module || inject_workspace_as_environment
323+
cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
324+
if use_puppet_strings
325+
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache,
326+
:object_types => PuppetLanguageServerSidecar::PuppetHelper.available_documentation_types,
327+
:root_path => PuppetLanguageServerSidecar::Workspace.root_path)
328+
else
329+
log_message(:warn, 'The workspace_aggregate action is only supported with the puppetstrings feature flag')
330+
{}
331+
end
332+
310333
when 'workspace_classes'
311334
null_cache = PuppetLanguageServerSidecar::Cache::Null.new
312335
return nil unless inject_workspace_as_module || inject_workspace_as_environment
313336
if use_puppet_strings
314337
cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
315338
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache,
316339
:object_types => [:class],
317-
:root_path => PuppetLanguageServerSidecar::Workspace.root_path)[:classes]
340+
:root_path => PuppetLanguageServerSidecar::Workspace.root_path).classes
318341
else
319342
PuppetLanguageServerSidecar::PuppetHelper.retrieve_classes(null_cache,
320343
:root_path => PuppetLanguageServerSidecar::Workspace.root_path)
@@ -328,7 +351,7 @@ def self.execute(options)
328351
cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
329352
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache,
330353
:object_types => [:function],
331-
:root_path => PuppetLanguageServerSidecar::Workspace.root_path)[:functions]
354+
:root_path => PuppetLanguageServerSidecar::Workspace.root_path).functions
332355
else
333356
PuppetLanguageServerSidecar::PuppetHelper.retrieve_functions(null_cache,
334357
:root_path => PuppetLanguageServerSidecar::Workspace.root_path)
@@ -341,7 +364,7 @@ def self.execute(options)
341364
cache = options[:disable_cache] ? PuppetLanguageServerSidecar::Cache::Null.new : PuppetLanguageServerSidecar::Cache::FileSystem.new
342365
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache,
343366
:object_types => [:type],
344-
:root_path => PuppetLanguageServerSidecar::Workspace.root_path)[:types]
367+
:root_path => PuppetLanguageServerSidecar::Workspace.root_path).types
345368
else
346369
PuppetLanguageServerSidecar::PuppetHelper.retrieve_types(null_cache)
347370
end

spec/languageserver-sidecar/integration/puppet-languageserver-sidecar/featureflag_puppetstrings/featureflag_puppetstrings_spec.rb

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,37 @@ def expect_same_array_content(a, b)
9292
end
9393
end
9494

95+
describe 'when running default_aggregate action' do
96+
let (:cmd_options) { ['--action', 'default_aggregate'] }
97+
98+
it 'should return a cachable deserializable aggregate object with all default metadata' do
99+
expect_empty_cache
100+
101+
result = run_sidecar(cmd_options)
102+
deserial = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new
103+
expect { deserial.from_json!(result) }.to_not raise_error
104+
105+
# The contents of the result are tested later
106+
107+
# Now run using cached information
108+
expect_populated_cache
109+
110+
result2 = run_sidecar(cmd_options)
111+
deserial2 = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new()
112+
expect { deserial2.from_json!(result2) }.to_not raise_error
113+
114+
deserial.class
115+
.instance_methods(false)
116+
.reject { |name| %i[to_json from_json! each_list append!].include?(name) }
117+
.each do |method_name|
118+
# There should be at least one item
119+
expect(deserial.send(method_name).count).to be > 0
120+
# Before and after should be the same
121+
expect_same_array_content(deserial.send(method_name), deserial2.send(method_name))
122+
end
123+
end
124+
end
125+
95126
describe 'when running default_classes action' do
96127
let (:cmd_options) { ['--action', 'default_classes'] }
97128

@@ -236,6 +267,37 @@ def expect_same_array_content(a, b)
236267
end
237268
end
238269

270+
describe 'when running workspace_aggregate action' do
271+
let (:cmd_options) { ['--action', 'workspace_aggregate', '--local-workspace', workspace] }
272+
273+
it 'should return a cachable deserializable aggregate object with all default metadata' do
274+
expect_empty_cache
275+
276+
result = run_sidecar(cmd_options)
277+
deserial = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new
278+
expect { deserial.from_json!(result) }.to_not raise_error
279+
280+
# The contents of the result are tested later
281+
282+
# Now run using cached information
283+
expect_populated_cache
284+
285+
result2 = run_sidecar(cmd_options)
286+
deserial2 = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new()
287+
expect { deserial2.from_json!(result2) }.to_not raise_error
288+
289+
deserial.class
290+
.instance_methods(false)
291+
.reject { |name| %i[to_json from_json! each_list append!].include?(name) }
292+
.each do |method_name|
293+
# There should be at least one item
294+
expect(deserial.send(method_name).count).to be > 0
295+
# Before and after should be the same
296+
expect_same_array_content(deserial.send(method_name), deserial2.send(method_name))
297+
end
298+
end
299+
end
300+
239301
describe 'when running workspace_classes action' do
240302
let (:cmd_options) { ['--action', 'workspace_classes', '--local-workspace', workspace] }
241303

@@ -348,6 +410,37 @@ def expect_same_array_content(a, b)
348410
end
349411
end
350412

413+
describe 'when running workspace_aggregate action' do
414+
let (:cmd_options) { ['--action', 'workspace_aggregate', '--local-workspace', workspace] }
415+
416+
it 'should return a cachable deserializable aggregate object with all default metadata' do
417+
expect_empty_cache
418+
419+
result = run_sidecar(cmd_options)
420+
deserial = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new
421+
expect { deserial.from_json!(result) }.to_not raise_error
422+
423+
# The contents of the result are tested later
424+
425+
# Now run using cached information
426+
expect_populated_cache
427+
428+
result2 = run_sidecar(cmd_options)
429+
deserial2 = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new()
430+
expect { deserial2.from_json!(result2) }.to_not raise_error
431+
432+
deserial.class
433+
.instance_methods(false)
434+
.reject { |name| %i[to_json from_json! each_list append!].include?(name) }
435+
.each do |method_name|
436+
# There should be at least one item
437+
expect(deserial.send(method_name).count).to be > 0
438+
# Before and after should be the same
439+
expect_same_array_content(deserial.send(method_name), deserial2.send(method_name))
440+
end
441+
end
442+
end
443+
351444
describe 'when running workspace_classes action' do
352445
let (:cmd_options) { ['--action', 'workspace_classes', '--local-workspace', workspace] }
353446

0 commit comments

Comments
 (0)