-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathdocument_store.rb
172 lines (148 loc) · 5.05 KB
/
document_store.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# frozen_string_literal: true
module PuppetLanguageServer
module DocumentStore
@documents = {}
@doc_mutex = Mutex.new
def self.set_document(uri, content, doc_version)
@doc_mutex.synchronize do
@documents[uri] = {
:content => content,
:version => doc_version
}
end
end
def self.remove_document(uri)
@doc_mutex.synchronize { @documents[uri] = nil }
end
def self.clear
@doc_mutex.synchronize { @documents.clear }
end
def self.document(uri, doc_version = nil)
@doc_mutex.synchronize do
return nil if @documents[uri].nil?
return nil unless doc_version.nil? || @documents[uri][:version] == doc_version
@documents[uri][:content].clone
end
end
def self.document_version(uri)
@doc_mutex.synchronize do
return nil if @documents[uri].nil?
@documents[uri][:version]
end
end
def self.document_uris
@doc_mutex.synchronize { @documents.keys.dup }
end
def self.document_type(uri)
case uri
when /\/Puppetfile$/i
:puppetfile
when /\.pp$/i
:manifest
when /\.epp$/i
:epp
else
:unknown
end
end
# Plan files https://puppet.com/docs/bolt/1.x/writing_plans.html#concept-4485
# exist in modules (requires metadata.json) and are in the `/plans` directory
def self.module_plan_file?(uri)
return false unless store_has_module_metadata?
relative_path = PuppetLanguageServer::UriHelper.relative_uri_path(PuppetLanguageServer::UriHelper.build_file_uri(store_root_path), uri, !windows?)
return false if relative_path.nil?
relative_path.start_with?('/plans/')
end
# Workspace management
WORKSPACE_CACHE_TTL_SECONDS = 60
def self.initialize_store(options = {})
@workspace_path = options[:workspace]
@workspace_info_cache = {
:expires => Time.new - 120
}
end
def self.expire_store_information
@doc_mutex.synchronize do
@workspace_info_cache[:expires] = Time.new - 120
end
end
def self.store_root_path
store_details[:root_path]
end
def self.store_has_module_metadata?
store_details[:has_metadatajson]
end
def self.store_has_environmentconf?
store_details[:has_environmentconf]
end
# Given a path, locate a metadata.json or environment.conf file to determine where the
# root of the module/control repo actually is
def self.find_root_path(path)
return nil if path.nil?
filepath = File.expand_path(path)
if dir_exist?(filepath)
directory = filepath
elsif file_exist?(filepath)
directory = File.dirname(filepath)
else
return nil
end
until directory.nil?
break if file_exist?(File.join(directory, 'metadata.json')) || file_exist?(File.join(directory, 'environment.conf'))
parent = File.dirname(directory)
# If the parent is the same as the original, then we've reached the end of the path chain
if parent == directory
directory = nil
else
directory = parent
end
end
directory
end
private_class_method :find_root_path
def self.store_details
return @workspace_info_cache unless @workspace_info_cache[:never_expires] || @workspace_info_cache[:expires] < Time.new
# TTL has expired, time to calculate the document store details
new_cache = {
:root_path => nil,
:has_environmentconf => false,
:has_metadatajson => false
}
if @workspace_path.nil?
# If we have never been given a local workspace path on the command line then there is really no
# way to know where the module file system path is. Therefore the root_path is nil and assume that
# environment.conf and metadata.json does not exist. And don't bother trying to re-evaluate
new_cache[:never_expires] = true
else
root_path = find_root_path(@workspace_path)
if root_path.nil?
new_cache[:root_path] = @workspace_path
else
new_cache[:root_path] = root_path
new_cache[:has_metadatajson] = file_exist?(File.join(root_path, 'metadata.json'))
new_cache[:has_environmentconf] = file_exist?(File.join(root_path, 'environment.conf'))
end
end
new_cache[:expires] = Time.new + WORKSPACE_CACHE_TTL_SECONDS
@doc_mutex.synchronize do
@workspace_info_cache = new_cache
end
@workspace_info_cache
end
private_class_method :store_details
def self.file_exist?(path)
File.exist?(path) && !File.directory?(path)
end
private_class_method :file_exist?
def self.dir_exist?(path)
Dir.exist?(path)
end
private_class_method :dir_exist?
def self.windows?
# Ruby only sets File::ALT_SEPARATOR on Windows and the Ruby standard
# library uses that to test what platform it's on.
!!File::ALT_SEPARATOR # rubocop:disable Style/DoubleNegation
end
private_class_method :windows?
end
end