Skip to content

Commit 3511698

Browse files
authored
Merge pull request #165 from glennsarti/add-aggregate-metadata
(GH-163) Use aggregate metadata actions for puppetstrings feature flag
2 parents 5bdcc4f + 376fc9e commit 3511698

File tree

10 files changed

+159
-44
lines changed

10 files changed

+159
-44
lines changed

lib/puppet-languageserver-sidecar/puppet_helper_puppetstrings.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def self.retrieve_via_puppet_strings(cache, options = {})
8383
end
8484

8585
# Remove Puppet3 functions which have a Puppet4 function already loaded
86-
if object_types.include?(:function)
86+
if object_types.include?(:function) && !result.functions.nil?
8787
pup4_functions = result.functions.select { |i| i.function_version == 4 }.map { |i| i.key }
8888
result.functions.reject! { |i| i.function_version == 3 && pup4_functions.include?(i.key) }
8989
end

lib/puppet-languageserver/puppet_helper.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ def self.cache
181181

182182
# Workspace Loading
183183
def self.load_workspace_async
184+
if PuppetLanguageServer.featureflag?('puppetstrings')
185+
return true if PuppetLanguageServer::DocumentStore.store_root_path.nil?
186+
sidecar_queue.enqueue('workspace_aggregate', ['--local-workspace', PuppetLanguageServer::DocumentStore.store_root_path])
187+
return true
188+
end
184189
load_workspace_classes_async
185190
load_workspace_functions_async
186191
load_workspace_types_async
@@ -226,5 +231,12 @@ def self.with_temporary_file(content)
226231
tempfile.delete if tempfile
227232
end
228233
private_class_method :with_temporary_file
234+
235+
def self.load_default_aggregate_async
236+
@default_classes_loaded = false if @default_classes_loaded.nil?
237+
@default_functions_loaded = false if @default_functions_loaded.nil?
238+
@default_types_loaded = false if @default_types_loaded.nil?
239+
sidecar_queue.enqueue('default_aggregate', [])
240+
end
229241
end
230242
end

lib/puppet-languageserver/puppet_helper/cache.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def initialize(_options = {})
1212
def import_sidecar_list!(list, section, origin = nil)
1313
section_object = section_to_object(section)
1414
return if section_object.nil?
15+
list = [] if list.nil?
1516

1617
@cache_lock.synchronize do
1718
# Remove the existing items

lib/puppet-languageserver/sidecar_protocol.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,11 @@ def types
385385
@aggregate[:types]
386386
end
387387

388+
def concat!(array)
389+
return if array.nil? || array.empty?
390+
array.each { |item| append!(item) }
391+
end
392+
388393
def append!(obj)
389394
list_for_object_class(obj.class) << obj
390395
end

lib/puppet-languageserver/sidecar_queue.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,24 @@ def execute_sync(action, additional_args, handle_errors = false)
6363
result = stdout.bytes.pack('U*')
6464

6565
case action.downcase
66+
when 'default_aggregate'
67+
lists = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new.from_json!(result)
68+
@cache.import_sidecar_list!(lists.classes, :class, :default)
69+
@cache.import_sidecar_list!(lists.functions, :function, :default)
70+
@cache.import_sidecar_list!(lists.types, :type, :default)
71+
72+
PuppetLanguageServer::PuppetHelper.assert_default_classes_loaded
73+
PuppetLanguageServer::PuppetHelper.assert_default_functions_loaded
74+
PuppetLanguageServer::PuppetHelper.assert_default_types_loaded
75+
76+
lists.each_list do |k, v|
77+
if v.nil?
78+
PuppetLanguageServer.log_message(:debug, "SidecarQueue Thread: default_aggregate returned no #{k}")
79+
else
80+
PuppetLanguageServer.log_message(:debug, "SidecarQueue Thread: default_aggregate returned #{v.count} #{k}")
81+
end
82+
end
83+
6684
when 'default_classes'
6785
list = PuppetLanguageServer::Sidecar::Protocol::PuppetClassList.new.from_json!(result)
6886
@cache.import_sidecar_list!(list, :class, :default)
@@ -90,6 +108,20 @@ def execute_sync(action, additional_args, handle_errors = false)
90108
when 'resource_list'
91109
return PuppetLanguageServer::Sidecar::Protocol::ResourceList.new.from_json!(result)
92110

111+
when 'workspace_aggregate'
112+
lists = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new.from_json!(result)
113+
@cache.import_sidecar_list!(lists.classes, :class, :workspace)
114+
@cache.import_sidecar_list!(lists.functions, :function, :workspace)
115+
@cache.import_sidecar_list!(lists.types, :type, :workspace)
116+
117+
lists.each_list do |k, v|
118+
if v.nil?
119+
PuppetLanguageServer.log_message(:debug, "SidecarQueue Thread: workspace_aggregate returned no #{k}")
120+
else
121+
PuppetLanguageServer.log_message(:debug, "SidecarQueue Thread: workspace_aggregate returned #{v.count} #{k}")
122+
end
123+
end
124+
93125
when 'workspace_classes'
94126
list = PuppetLanguageServer::Sidecar::Protocol::PuppetClassList.new.from_json!(result)
95127
@cache.import_sidecar_list!(list, :class, :workspace)

lib/puppet_languageserver.rb

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ def self.active?
2424
@server_is_active
2525
end
2626

27+
def self.configure_featureflags(flags)
28+
@flags = flags
29+
end
30+
31+
def self.featureflag?(flagname)
32+
return false if @flags.nil? || @flags.empty?
33+
@flags.include?(flagname)
34+
end
35+
2736
def self.require_gems(options)
2837
original_verbose = $VERBOSE
2938
$VERBOSE = nil
@@ -83,6 +92,15 @@ def self.require_gems(options)
8392
require File.expand_path(File.join(File.dirname(__FILE__), 'puppet-languageserver', lib))
8493
end
8594
end
95+
96+
# Validate the feature flags
97+
unless options[:flags].nil? || options[:flags].empty?
98+
flags = options[:flags]
99+
log_message(:debug, "Detected feature flags [#{flags.join(', ')}]")
100+
101+
configure_featureflags(flags)
102+
end
103+
86104
@server_is_active = true
87105
ensure
88106
$VERBOSE = original_verbose
@@ -223,17 +241,25 @@ def self.init_puppet_worker(options)
223241

224242
log_message(:info, "Using Facter v#{Facter.version}")
225243
if options[:preload_puppet]
226-
log_message(:info, 'Preloading Puppet Types (Async)...')
227-
PuppetLanguageServer::PuppetHelper.load_default_types_async
244+
if featureflag?('puppetstrings')
245+
log_message(:info, 'Preloading Default metadata (Async)...')
246+
PuppetLanguageServer::PuppetHelper.load_default_aggregate_async
228247

229-
log_message(:info, 'Preloading Facter (Async)...')
230-
PuppetLanguageServer::FacterHelper.load_facts_async
248+
log_message(:info, 'Preloading Facter (Async)...')
249+
PuppetLanguageServer::FacterHelper.load_facts_async
250+
else
251+
log_message(:info, 'Preloading Puppet Types (Async)...')
252+
PuppetLanguageServer::PuppetHelper.load_default_types_async
231253

232-
log_message(:info, 'Preloading Functions (Async)...')
233-
PuppetLanguageServer::PuppetHelper.load_default_functions_async
254+
log_message(:info, 'Preloading Facter (Async)...')
255+
PuppetLanguageServer::FacterHelper.load_facts_async
234256

235-
log_message(:info, 'Preloading Classes (Async)...')
236-
PuppetLanguageServer::PuppetHelper.load_default_classes_async
257+
log_message(:info, 'Preloading Functions (Async)...')
258+
PuppetLanguageServer::PuppetHelper.load_default_functions_async
259+
260+
log_message(:info, 'Preloading Classes (Async)...')
261+
PuppetLanguageServer::PuppetHelper.load_default_classes_async
262+
end
237263

238264
if PuppetLanguageServer::DocumentStore.store_has_module_metadata? || PuppetLanguageServer::DocumentStore.store_has_environmentconf?
239265
log_message(:info, 'Preloading Workspace (Async)...')

lib/puppet_languageserver_sidecar.rb

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ def self.inject_workspace_as_environment
256256
def self.execute(options)
257257
use_puppet_strings = featureflag?('puppetstrings')
258258

259+
log_message(:debug, "Executing #{options[:action]} action")
259260
case options[:action].downcase
260261
when 'noop'
261262
[]
@@ -265,8 +266,7 @@ def self.execute(options)
265266
if use_puppet_strings
266267
PuppetLanguageServerSidecar::PuppetHelper.retrieve_via_puppet_strings(cache, :object_types => PuppetLanguageServerSidecar::PuppetHelper.available_documentation_types)
267268
else
268-
log_message(:warn, 'The default_aggregate action is only supported with the puppetstrings feature flag')
269-
{}
269+
create_aggregate(cache)
270270
end
271271

272272
when 'default_classes'
@@ -326,8 +326,7 @@ def self.execute(options)
326326
:object_types => PuppetLanguageServerSidecar::PuppetHelper.available_documentation_types,
327327
:root_path => PuppetLanguageServerSidecar::Workspace.root_path)
328328
else
329-
log_message(:warn, 'The workspace_aggregate action is only supported with the puppetstrings feature flag')
330-
{}
329+
create_aggregate(PuppetLanguageServerSidecar::Cache::Null.new, PuppetLanguageServerSidecar::Workspace.root_path)
331330
end
332331

333332
when 'workspace_classes'
@@ -374,6 +373,15 @@ def self.execute(options)
374373
end
375374
end
376375

376+
def self.create_aggregate(cache, root_path = nil)
377+
result = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new
378+
result.concat!(PuppetLanguageServerSidecar::PuppetHelper.retrieve_types(cache, :root_path => root_path))
379+
result.concat!(PuppetLanguageServerSidecar::PuppetHelper.retrieve_functions(cache, :root_path => root_path))
380+
result.concat!(PuppetLanguageServerSidecar::PuppetHelper.retrieve_classes(cache, :root_path => root_path))
381+
result
382+
end
383+
private_class_method :create_aggregate
384+
377385
def self.output(result, options)
378386
if options[:output].nil? || options[:output].empty?
379387
STDOUT.binmode

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

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,10 @@ def expect_same_array_content(a, b)
111111
deserial2 = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new()
112112
expect { deserial2.from_json!(result2) }.to_not raise_error
113113

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))
114+
deserial.each_list do |key, value|
115+
# There should be at least one item per list in the aggregate
116+
expect(value.count).to be > 0
117+
expect_same_array_content(value, deserial2.send(key))
122118
end
123119
end
124120
end
@@ -270,7 +266,7 @@ def expect_same_array_content(a, b)
270266
describe 'when running workspace_aggregate action' do
271267
let (:cmd_options) { ['--action', 'workspace_aggregate', '--local-workspace', workspace] }
272268

273-
it 'should return a cachable deserializable aggregate object with all default metadata' do
269+
it 'should return a cachable deserializable aggregate object with all workspace metadata' do
274270
expect_empty_cache
275271

276272
result = run_sidecar(cmd_options)
@@ -286,14 +282,10 @@ def expect_same_array_content(a, b)
286282
deserial2 = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new()
287283
expect { deserial2.from_json!(result2) }.to_not raise_error
288284

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))
285+
deserial.each_list do |key, value|
286+
# There should be at least one item per list in the aggregate
287+
expect(value.count).to be > 0
288+
expect_same_array_content(value, deserial2.send(key))
297289
end
298290
end
299291
end
@@ -429,14 +421,10 @@ def expect_same_array_content(a, b)
429421
deserial2 = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new()
430422
expect { deserial2.from_json!(result2) }.to_not raise_error
431423

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))
424+
deserial.each_list do |key, value|
425+
# There should be at least one item per list in the aggregate
426+
expect(value.count).to be > 0
427+
expect_same_array_content(value, deserial2.send(key))
440428
end
441429
end
442430
end

spec/languageserver-sidecar/integration/puppet-languageserver-sidecar/puppet-languageserver-sidecar_spec.rb

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,17 @@ def with_temporary_file(content)
4848
describe 'when running default_aggregate action' do
4949
let (:cmd_options) { ['--action', 'default_aggregate'] }
5050

51-
it 'should return an empty hash' do
51+
it 'should return a deserializable aggregate object with all default metadata' do
5252
result = run_sidecar(cmd_options)
53+
deserial = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new
54+
expect { deserial.from_json!(result) }.to_not raise_error
55+
56+
# The contents of the result are tested later
5357

54-
expect(result).to eq('{}')
58+
# There should be at least one item per list in the aggregate
59+
deserial.each_list do |_, v|
60+
expect(v.count).to be > 0
61+
end
5562
end
5663
end
5764

@@ -139,10 +146,17 @@ def with_temporary_file(content)
139146
describe 'when running workspace_aggregate action' do
140147
let (:cmd_options) { ['--action', 'workspace_aggregate', '--local-workspace', workspace] }
141148

142-
it 'should return an empty hash' do
149+
it 'should return a deserializable aggregate object with all workspace metadata' do
143150
result = run_sidecar(cmd_options)
151+
deserial = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new
152+
expect { deserial.from_json!(result) }.to_not raise_error
153+
154+
# The contents of the result are tested later
144155

145-
expect(result).to eq('{}')
156+
# There should be at least one item per list in the aggregate
157+
deserial.each_list do |_, v|
158+
expect(v.count).to be > 0
159+
end
146160
end
147161
end
148162

@@ -235,10 +249,17 @@ def with_temporary_file(content)
235249
describe 'when running workspace_aggregate action' do
236250
let (:cmd_options) { ['--action', 'workspace_aggregate', '--local-workspace', workspace] }
237251

238-
it 'should return an empty hash' do
252+
it 'should return a deserializable aggregate object with all workspace metadata' do
239253
result = run_sidecar(cmd_options)
254+
deserial = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new
255+
expect { deserial.from_json!(result) }.to_not raise_error
240256

241-
expect(result).to eq('{}')
257+
# The contents of the result are tested later
258+
259+
# There should be at least one item per list in the aggregate
260+
deserial.each_list do |_, v|
261+
expect(v.count).to be > 0
262+
end
242263
end
243264
end
244265

spec/languageserver/integration/puppet-languageserver/sidecar_queue_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,28 @@ def exitstatus
6262
end
6363

6464
describe '#execute_sync' do
65+
context 'default_aggregate action' do
66+
let(:action) { 'default_aggregate' }
67+
68+
it 'should deserialize the json, import into the cache and assert default classes are loaded' do
69+
fixture = PuppetLanguageServer::Sidecar::Protocol::AggregateMetadata.new
70+
fixture.append!(random_sidecar_puppet_class)
71+
fixture.append!(random_sidecar_puppet_function)
72+
fixture.append!(random_sidecar_puppet_type)
73+
sidecar_response = [fixture.to_json, 'stderr', SuccessStatus.new]
74+
75+
expect(subject).to receive(:run_sidecar).and_return(sidecar_response)
76+
expect(PuppetLanguageServer::PuppetHelper).to receive(:assert_default_classes_loaded)
77+
expect(PuppetLanguageServer::PuppetHelper).to receive(:assert_default_functions_loaded)
78+
expect(PuppetLanguageServer::PuppetHelper).to receive(:assert_default_types_loaded)
79+
80+
subject.execute_sync(action, [])
81+
expect(cache.object_by_name(:class, fixture.classes[0].key)).to_not be_nil
82+
expect(cache.object_by_name(:function, fixture.functions[0].key)).to_not be_nil
83+
expect(cache.object_by_name(:type, fixture.types[0].key)).to_not be_nil
84+
end
85+
end
86+
6587
context 'default_classes action' do
6688
let(:action) { 'default_classes' }
6789

0 commit comments

Comments
 (0)