abide_dev_utils 0.9.7 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +7 -1
- data/Gemfile.lock +82 -64
- data/Rakefile +28 -0
- data/abide_dev_utils.gemspec +3 -1
- data/lib/abide_dev_utils/cem/benchmark.rb +291 -0
- data/lib/abide_dev_utils/cem/coverage_report.rb +348 -0
- data/lib/abide_dev_utils/cem/generate/reference.rb +116 -0
- data/lib/abide_dev_utils/cem/generate.rb +10 -0
- data/lib/abide_dev_utils/cem/mapping/mapper.rb +155 -0
- data/lib/abide_dev_utils/cem.rb +74 -0
- data/lib/abide_dev_utils/cli/cem.rb +153 -0
- data/lib/abide_dev_utils/cli/jira.rb +1 -1
- data/lib/abide_dev_utils/cli/xccdf.rb +15 -1
- data/lib/abide_dev_utils/cli.rb +2 -0
- data/lib/abide_dev_utils/errors/cem.rb +22 -0
- data/lib/abide_dev_utils/errors/general.rb +8 -2
- data/lib/abide_dev_utils/errors/ppt.rb +4 -0
- data/lib/abide_dev_utils/errors.rb +6 -0
- data/lib/abide_dev_utils/files.rb +34 -0
- data/lib/abide_dev_utils/markdown.rb +104 -0
- data/lib/abide_dev_utils/ppt/facter_utils.rb +140 -0
- data/lib/abide_dev_utils/ppt/hiera.rb +297 -0
- data/lib/abide_dev_utils/ppt/puppet_module.rb +74 -0
- data/lib/abide_dev_utils/ppt.rb +3 -5
- data/lib/abide_dev_utils/validate.rb +14 -0
- data/lib/abide_dev_utils/version.rb +1 -1
- data/lib/abide_dev_utils/xccdf/diff/benchmark/number_title.rb +270 -0
- data/lib/abide_dev_utils/xccdf/diff/benchmark/profile.rb +104 -0
- data/lib/abide_dev_utils/xccdf/diff/benchmark/property.rb +127 -0
- data/lib/abide_dev_utils/xccdf/diff/benchmark/property_existence.rb +47 -0
- data/lib/abide_dev_utils/xccdf/diff/benchmark.rb +267 -0
- data/lib/abide_dev_utils/xccdf/diff/utils.rb +30 -0
- data/lib/abide_dev_utils/xccdf/diff.rb +233 -0
- data/lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb +118 -0
- data/lib/abide_dev_utils/xccdf/parser/objects/numbered_object.rb +104 -0
- data/lib/abide_dev_utils/xccdf/parser/objects.rb +741 -0
- data/lib/abide_dev_utils/xccdf/parser.rb +52 -0
- data/lib/abide_dev_utils/xccdf.rb +14 -124
- data/new_diff.rb +48 -0
- metadata +60 -9
- data/lib/abide_dev_utils/ppt/coverage.rb +0 -86
@@ -1,7 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'abide_dev_utils/validate'
|
4
|
+
|
3
5
|
module AbideDevUtils
|
4
6
|
module Files
|
7
|
+
class Reader
|
8
|
+
def self.read(path, raw: false, safe: true, opts: {})
|
9
|
+
AbideDevUtils::Validate.file(path)
|
10
|
+
return File.read(path) if raw
|
11
|
+
|
12
|
+
extension = File.extname(path)
|
13
|
+
case extension
|
14
|
+
when /\.yaml|\.yml/
|
15
|
+
require 'yaml'
|
16
|
+
if safe
|
17
|
+
YAML.safe_load(File.read(path))
|
18
|
+
else
|
19
|
+
YAML.load_file(path)
|
20
|
+
end
|
21
|
+
when '.json'
|
22
|
+
require 'json'
|
23
|
+
return JSON.parse(File.read(path), opts) if safe
|
24
|
+
|
25
|
+
JSON.parse!(File.read(path), opts)
|
26
|
+
when '.xml'
|
27
|
+
require 'nokogiri'
|
28
|
+
File.open(path, 'r') do |file|
|
29
|
+
Nokogiri::XML.parse(file) do |config|
|
30
|
+
config.strict.noblanks.norecover
|
31
|
+
end
|
32
|
+
end
|
33
|
+
else
|
34
|
+
File.read(path)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
5
39
|
class Writer
|
6
40
|
MSG_EXT_APPEND = 'Appending %s extension to file'
|
7
41
|
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbideDevUtils
|
4
|
+
# Formats text for output in markdown
|
5
|
+
class Markdown
|
6
|
+
def initialize(file, with_toc: true)
|
7
|
+
@file = file
|
8
|
+
@with_toc = with_toc
|
9
|
+
@toc = ["## Table of Contents\n"]
|
10
|
+
@body = []
|
11
|
+
@title = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_markdown
|
15
|
+
toc = @toc.join("\n")
|
16
|
+
body = @body.join("\n")
|
17
|
+
"#{@title}\n#{toc}\n\n#{body}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_file
|
21
|
+
File.write(@file, to_markdown)
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(name, *args, &block)
|
25
|
+
if name.to_s.start_with?('add_')
|
26
|
+
add(name.to_s.sub('add_', '').to_sym, *args, &block)
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def respond_to_missing?(name, include_private = false)
|
33
|
+
name.to_s.start_with?('add_') || super
|
34
|
+
end
|
35
|
+
|
36
|
+
def title(text)
|
37
|
+
"# #{text}\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
def h1(text)
|
41
|
+
"## #{text}\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
def h2(text)
|
45
|
+
"### #{text}\n"
|
46
|
+
end
|
47
|
+
|
48
|
+
def h3(text)
|
49
|
+
"#### #{text}\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
def ul(text, indent: 0)
|
53
|
+
indented_text = []
|
54
|
+
indent.times { indented_text << ' ' } if indent.positive?
|
55
|
+
|
56
|
+
indented_text << "* #{text}"
|
57
|
+
indented_text.join
|
58
|
+
end
|
59
|
+
|
60
|
+
def bold(text)
|
61
|
+
"**#{text}**"
|
62
|
+
end
|
63
|
+
|
64
|
+
def italic(text)
|
65
|
+
"*#{text}*"
|
66
|
+
end
|
67
|
+
|
68
|
+
def link(text, url, anchor: false)
|
69
|
+
url = anchor(url) if anchor
|
70
|
+
"[#{text}](#{url.downcase})"
|
71
|
+
end
|
72
|
+
|
73
|
+
def code(text)
|
74
|
+
"\`#{text}\`"
|
75
|
+
end
|
76
|
+
|
77
|
+
def code_block(text, language: nil)
|
78
|
+
language.nil? ? "```\n#{text}\n```" : "```#{language}\n#{text}\n```"
|
79
|
+
end
|
80
|
+
|
81
|
+
def anchor(text)
|
82
|
+
"##{text.downcase.gsub(%r{\s|_}, '-').tr('.,\'"()', '')}"
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def add(type, text, *args, **kwargs)
|
88
|
+
@toc << ul(link(text, text, anchor: true), indent: 0) if @with_toc && type == :h1
|
89
|
+
|
90
|
+
case type.to_sym
|
91
|
+
when :title
|
92
|
+
@title = title(text)
|
93
|
+
when :ul
|
94
|
+
@body << ul(text, indent: kwargs.fetch(:indent, 0))
|
95
|
+
when :link
|
96
|
+
@body << link(text, args.first, anchor: kwargs.fetch(:anchor, false))
|
97
|
+
when :code_block
|
98
|
+
@body << code_block(text, language: kwargs.fetch(:language, nil))
|
99
|
+
else
|
100
|
+
@body << send(type, text)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'facterdb'
|
5
|
+
|
6
|
+
module AbideDevUtils
|
7
|
+
module Ppt
|
8
|
+
# Methods relating to Facter
|
9
|
+
module FacterUtils
|
10
|
+
class << self
|
11
|
+
attr_writer :current_version
|
12
|
+
|
13
|
+
def current_version
|
14
|
+
return latest_version unless defined?(@current_version)
|
15
|
+
|
16
|
+
@current_version
|
17
|
+
end
|
18
|
+
|
19
|
+
def use_version(version)
|
20
|
+
self.current_version = version
|
21
|
+
current_version
|
22
|
+
end
|
23
|
+
|
24
|
+
def with_version(version, reset: true)
|
25
|
+
return unless block_given?
|
26
|
+
|
27
|
+
old_ver = current_version.dup
|
28
|
+
use_version(version)
|
29
|
+
output = yield
|
30
|
+
use_version(old_ver) if reset
|
31
|
+
output
|
32
|
+
end
|
33
|
+
|
34
|
+
def fact_files
|
35
|
+
@fact_files ||= FacterDB.facterdb_fact_files.each_with_object({}) do |f, h|
|
36
|
+
facter_version = file_facter_version(f)
|
37
|
+
h[facter_version] = [] unless h.key?(facter_version)
|
38
|
+
h[facter_version] << f
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def fact_sets(facter_version: current_version)
|
43
|
+
@fact_sets ||= fact_files[facter_version].each_with_object({}) do |fp, h|
|
44
|
+
h[facter_version] = [] unless h.key?(facter_version)
|
45
|
+
h[facter_version] << JSON.parse(File.read(fp))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def file_facter_version(path)
|
50
|
+
File.basename(File.dirname(path))
|
51
|
+
end
|
52
|
+
|
53
|
+
def all_versions
|
54
|
+
@all_versions ||= fact_files.keys.sort
|
55
|
+
end
|
56
|
+
|
57
|
+
def latest_version
|
58
|
+
@latest_version ||= all_versions[-1]
|
59
|
+
end
|
60
|
+
|
61
|
+
def previous_major_version(facter_version = current_version)
|
62
|
+
@previous_major_version_map ||= {}
|
63
|
+
|
64
|
+
majver = facter_version.split('.')[0]
|
65
|
+
return @previous_major_version_map[majver] if @previous_major_version_map.key?(majver)
|
66
|
+
|
67
|
+
prev_majver = (majver.to_i - 1).to_s
|
68
|
+
prev_ver = all_versions.select { |v| v.start_with?(prev_majver) }.max
|
69
|
+
return nil if prev_ver.to_i < 1
|
70
|
+
|
71
|
+
@previous_major_version_map[majver] = prev_ver
|
72
|
+
@previous_major_version_map[majver]
|
73
|
+
end
|
74
|
+
|
75
|
+
def recurse_versions(version = current_version, &block)
|
76
|
+
use_version(version)
|
77
|
+
output = yield
|
78
|
+
return output unless output.nil? || output.empty?
|
79
|
+
|
80
|
+
prev_ver = previous_major_version(version).dup
|
81
|
+
return nil if prev_ver.nil?
|
82
|
+
|
83
|
+
recurse_versions(prev_ver, &block)
|
84
|
+
rescue SystemStackError
|
85
|
+
locals = {
|
86
|
+
prev_ver_map: @previous_major_version_map,
|
87
|
+
current_version: current_version,
|
88
|
+
}
|
89
|
+
raise "Failed to find output while recursing versions. Locals: #{locals}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def recursive_facts_for_os(os_name, os_release_major = nil, os_hardware: 'x86_64')
|
93
|
+
saved_ver = current_version.dup
|
94
|
+
output = recurse_versions do
|
95
|
+
facts_for_os(os_name, os_release_major, os_hardware: os_hardware)
|
96
|
+
end
|
97
|
+
use_version(saved_ver)
|
98
|
+
output
|
99
|
+
end
|
100
|
+
|
101
|
+
def facts_for_os(os_name, os_release_major = nil, os_hardware: 'x86_64', facter_version: current_version)
|
102
|
+
cache_key = "#{os_name.downcase}_#{os_release_major}_#{os_hardware}"
|
103
|
+
return @facts_for_os[cache_key] if @facts_for_os&.key?(cache_key)
|
104
|
+
|
105
|
+
fact_file = fact_files[facter_version].find do |f|
|
106
|
+
name_parts = File.basename(f, '.facts').split('-')
|
107
|
+
name = name_parts[0]
|
108
|
+
relmaj = name_parts.length >= 3 ? name_parts[1] : nil
|
109
|
+
hardware = name_parts[-1]
|
110
|
+
name == os_name.downcase && relmaj == os_release_major && hardware == os_hardware
|
111
|
+
end
|
112
|
+
return if fact_file.nil? || fact_file.empty?
|
113
|
+
|
114
|
+
@facts_for_os = {} unless defined?(@facts_for_os)
|
115
|
+
@facts_for_os[cache_key] = JSON.parse(File.read(fact_file))
|
116
|
+
@facts_for_os[cache_key]
|
117
|
+
end
|
118
|
+
|
119
|
+
def resolve_dot_path(dot_path, facter_version: latest_version)
|
120
|
+
path_array = dot_path.delete_prefix('facts.').split('.')
|
121
|
+
resolved = fact_sets[facter_version].map do |fs|
|
122
|
+
fs.dig(*path_array)
|
123
|
+
end
|
124
|
+
resolved.compact.uniq
|
125
|
+
end
|
126
|
+
|
127
|
+
def resolve_related_dot_paths(*dot_paths, facter_version: current_version)
|
128
|
+
resolved = []
|
129
|
+
fact_sets[facter_version].map do |fs|
|
130
|
+
resolved << dot_paths.map do |p|
|
131
|
+
path_array = p.delete_prefix('facts.').split('.')
|
132
|
+
fs.dig(*path_array)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
resolved
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,297 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'abide_dev_utils/validate'
|
5
|
+
require 'abide_dev_utils/ppt/facter_utils'
|
6
|
+
|
7
|
+
module AbideDevUtils
|
8
|
+
module Ppt
|
9
|
+
# Module for working with Hiera
|
10
|
+
module Hiera
|
11
|
+
INTERP_PATTERN = /%{([^{}]+)}/.freeze
|
12
|
+
FACT_PATTERN = /%{facts\.([^{}]+)}/.freeze
|
13
|
+
DEFAULT_FACTER_VERSION = '3.14'
|
14
|
+
DEFAULT_CONFIG_FILE = 'hiera.yaml'
|
15
|
+
|
16
|
+
def self.facter_version=(version)
|
17
|
+
@facter_version = AbideDevUtils::Ppt::FacterUtils.use_version(version.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.facter_version
|
21
|
+
@facter_version
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.default_datadir=(dir)
|
25
|
+
edir = File.expand_path(dir)
|
26
|
+
raise "Dir #{edir} not found" unless File.directory?(edir)
|
27
|
+
|
28
|
+
@default_datadir = edir
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.default_datadir
|
32
|
+
@default_datadir
|
33
|
+
end
|
34
|
+
|
35
|
+
# Represents a Hiera configuration file
|
36
|
+
class Config
|
37
|
+
def initialize(path = DEFAULT_CONFIG_FILE, facter_version: DEFAULT_FACTER_VERSION)
|
38
|
+
@path = File.expand_path(path)
|
39
|
+
raise "Hiera config file at path #{@path} not found!" unless File.file?(@path)
|
40
|
+
|
41
|
+
@conf = YAML.load_file(File.expand_path(path))
|
42
|
+
@by_name_path_store = {}
|
43
|
+
AbideDevUtils::Ppt::Hiera.default_datadir = @conf['defaults']['datadir'] if @conf['defaults'].key?('datadir')
|
44
|
+
AbideDevUtils::Ppt::Hiera.facter_version = facter_version
|
45
|
+
end
|
46
|
+
|
47
|
+
def hierarchy
|
48
|
+
@hierarchy ||= Hierarchy.new(@conf['hierarchy'], AbideDevUtils::Ppt::Hiera.default_datadir)
|
49
|
+
end
|
50
|
+
|
51
|
+
def version
|
52
|
+
@version ||= @conf['version']
|
53
|
+
end
|
54
|
+
|
55
|
+
def defaults
|
56
|
+
@defaults ||= @conf['defaults']
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_datadir
|
60
|
+
AbideDevUtils::Ppt::Hiera.default_datadir
|
61
|
+
end
|
62
|
+
|
63
|
+
def default_data_hash
|
64
|
+
@default_data_hash ||= defaults['data_hash']
|
65
|
+
end
|
66
|
+
|
67
|
+
def local_hiera_files(hierarchy_name: nil)
|
68
|
+
if hierarchy_name
|
69
|
+
hierarchy.entry_by_name(hierarchy_name).local_files
|
70
|
+
else
|
71
|
+
hierarchy.entries.map(&:local_files).flatten
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def local_hiera_files_with_fact(fact_str, value = nil, hierarchy_name: nil)
|
76
|
+
if hierarchy_name
|
77
|
+
hierarchy.entry_by_name(hierarchy_name).local_files_with_fact(fact_str, value)
|
78
|
+
else
|
79
|
+
hierarchy.entries.map { |e| e.local_files_with_fact(fact_str, value) }.flatten
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def local_hiera_files_with_facts(*fact_arrays, hierarchy_name: nil)
|
84
|
+
if hierarchy_name
|
85
|
+
hierarchy.entry_by_name(hierarchy_name).local_files_with_facts(*fact_arrays)
|
86
|
+
else
|
87
|
+
hierarchy.entries.map { |e| e.local_files_with_fact(*fact_arrays) }.flatten
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Represents the "hierarchy" section of the Hiera config
|
93
|
+
class Hierarchy
|
94
|
+
attr_reader :default_datadir, :entries
|
95
|
+
|
96
|
+
def initialize(hierarchy, default_datadir)
|
97
|
+
@hierarchy = hierarchy
|
98
|
+
@default_datadir = File.expand_path(default_datadir)
|
99
|
+
@entries = @hierarchy.map { |h| HierarchyEntry.new(h) }
|
100
|
+
@by_name_store = {}
|
101
|
+
@paths_by_name_store = {}
|
102
|
+
end
|
103
|
+
|
104
|
+
def method_missing(m, *args, &block)
|
105
|
+
if %i[each each_with_object each_with_index select reject map].include?(m)
|
106
|
+
@entries.send(m, *args, &block)
|
107
|
+
else
|
108
|
+
super
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def respond_to_missing?(m, include_private = false)
|
113
|
+
%i[each each_with_object each_with_index select reject map].include?(m) || super
|
114
|
+
end
|
115
|
+
|
116
|
+
def entry_by_name(name)
|
117
|
+
AbideDevUtils::Validate.populated_string(name)
|
118
|
+
return @by_name_store[name] if @by_name_store[name]
|
119
|
+
|
120
|
+
found = @entries.select { |x| x.name == name }
|
121
|
+
AbideDevUtils::Validate.not_empty(found, "Hierarchy entry for name '#{name}' not found")
|
122
|
+
@by_name_store[name] = found[0]
|
123
|
+
@by_name_store[name]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Represents a single entry in the hierarchy
|
128
|
+
class HierarchyEntry
|
129
|
+
attr_reader :entry, :name, :paths
|
130
|
+
|
131
|
+
def initialize(entry)
|
132
|
+
@entry = entry
|
133
|
+
@name = @entry['name']
|
134
|
+
@paths = @entry.key?('path') ? create_paths(@entry['path']) : create_paths(*@entry['paths'])
|
135
|
+
end
|
136
|
+
|
137
|
+
def local_files
|
138
|
+
@local_files ||= paths.map(&:local_files).flatten
|
139
|
+
end
|
140
|
+
|
141
|
+
def local_files_with_fact(fact_str, value = nil)
|
142
|
+
paths.map { |p| p.local_files_with_fact(fact_str, value) }.flatten
|
143
|
+
end
|
144
|
+
|
145
|
+
def local_files_with_facts(*fact_arrays)
|
146
|
+
paths.map { |p| p.local_files_with_facts(*fact_arrays) }.flatten
|
147
|
+
end
|
148
|
+
|
149
|
+
def to_s
|
150
|
+
name
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def create_paths(*paths)
|
156
|
+
paths.map { |p| HierarchyEntryPath.new(p) }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Represents a Hiera entry path
|
161
|
+
class HierarchyEntryPath
|
162
|
+
attr_reader :path
|
163
|
+
|
164
|
+
def initialize(path)
|
165
|
+
@path = path
|
166
|
+
end
|
167
|
+
|
168
|
+
def path_parts
|
169
|
+
@path_parts ||= path.split('/')
|
170
|
+
end
|
171
|
+
|
172
|
+
def interpolation
|
173
|
+
@interpolation ||= path.scan(INTERP_PATTERN).flatten
|
174
|
+
end
|
175
|
+
|
176
|
+
def interpolation?
|
177
|
+
!interpolation.empty?
|
178
|
+
end
|
179
|
+
|
180
|
+
def facts
|
181
|
+
@facts ||= path.scan(FACT_PATTERN).flatten
|
182
|
+
end
|
183
|
+
|
184
|
+
def facts?
|
185
|
+
!facts.empty?
|
186
|
+
end
|
187
|
+
|
188
|
+
def possible_fact_values
|
189
|
+
@possible_fact_values ||= AbideDevUtils::Ppt::FacterUtils.resolve_related_dot_paths(*facts)
|
190
|
+
end
|
191
|
+
|
192
|
+
def local_files
|
193
|
+
@local_files ||= find_local_files.flatten
|
194
|
+
end
|
195
|
+
|
196
|
+
def local_files_with_fact(fact_str, value = nil)
|
197
|
+
local_files.select do |lf|
|
198
|
+
# The match below is case-insentive for convenience
|
199
|
+
(value.nil? ? lf.fact_values.key?(fact_str) : (lf.fact_values[fact_str]&.match?(/#{value}/i) || false))
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def local_files_with_facts(*fact_arrays)
|
204
|
+
return local_files_with_fact(*fact_arrays[0]) if fact_arrays.length == 1
|
205
|
+
|
206
|
+
start_fact = fact_arrays[0][0]
|
207
|
+
last_fact = nil
|
208
|
+
memo = {}
|
209
|
+
with_facts = []
|
210
|
+
fact_arrays.each do |fa|
|
211
|
+
cur_fact = fa[0]
|
212
|
+
memo[cur_fact] = local_files_with_fact(*fa)
|
213
|
+
if cur_fact == start_fact
|
214
|
+
with_facts = memo[cur_fact]
|
215
|
+
else
|
216
|
+
last_paths = memo[last_fact].map(&:path)
|
217
|
+
cur_paths = memo[cur_fact].map(&:path)
|
218
|
+
with_facts.reject! { |x| last_paths.difference(cur_paths).include?(x.path) }
|
219
|
+
end
|
220
|
+
last_fact = cur_fact
|
221
|
+
end
|
222
|
+
with_facts.flatten.uniq(&:path)
|
223
|
+
end
|
224
|
+
|
225
|
+
def to_s
|
226
|
+
path
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
def find_local_files
|
232
|
+
new_paths = []
|
233
|
+
possible_fact_values.each do |pfv|
|
234
|
+
new_path = path.dup
|
235
|
+
pfv.each do |v|
|
236
|
+
next unless v
|
237
|
+
|
238
|
+
new_path.sub!(FACT_PATTERN, v)
|
239
|
+
end
|
240
|
+
new_paths << EntryPathLocalFile.new(new_path, facts, possible_fact_values)
|
241
|
+
end
|
242
|
+
new_paths.uniq(&:path).select(&:exist?)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Represents a local file derived from a Hiera path
|
247
|
+
class EntryPathLocalFile
|
248
|
+
attr_reader :path, :facts
|
249
|
+
|
250
|
+
def initialize(path, facts, possible_fact_values)
|
251
|
+
@path = File.expand_path(File.join(AbideDevUtils::Ppt::Hiera.default_datadir, path))
|
252
|
+
@facts = facts
|
253
|
+
@possible_fact_values = possible_fact_values
|
254
|
+
end
|
255
|
+
|
256
|
+
def fact_values
|
257
|
+
@fact_values ||= fact_values_for_path
|
258
|
+
end
|
259
|
+
|
260
|
+
def path_parts
|
261
|
+
@path_parts ||= path.split('/')
|
262
|
+
end
|
263
|
+
|
264
|
+
def exist?
|
265
|
+
File.file?(path)
|
266
|
+
end
|
267
|
+
|
268
|
+
def to_s
|
269
|
+
path
|
270
|
+
end
|
271
|
+
|
272
|
+
def to_h
|
273
|
+
{
|
274
|
+
path: path,
|
275
|
+
facts: facts
|
276
|
+
}
|
277
|
+
end
|
278
|
+
|
279
|
+
private
|
280
|
+
|
281
|
+
def fact_values_for_path
|
282
|
+
no_fext_path_parts = path_parts.map { |part| File.basename(part, '.yaml') }
|
283
|
+
valid_fact_values = @possible_fact_values.select do |pfv|
|
284
|
+
pfv.all? { |v| no_fext_path_parts.include?(v) }
|
285
|
+
end
|
286
|
+
valid_fact_values.uniq! # Removes duplicate arrays, not duplicate fact values
|
287
|
+
valid_fact_values.flatten!
|
288
|
+
return {} if valid_fact_values.empty?
|
289
|
+
|
290
|
+
fact_vals = {}
|
291
|
+
facts.each_index { |idx| fact_vals[facts[idx]] = valid_fact_values[idx] }
|
292
|
+
fact_vals
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'yaml'
|
5
|
+
require 'abide_dev_utils/validate'
|
6
|
+
require 'abide_dev_utils/ppt/hiera'
|
7
|
+
|
8
|
+
module AbideDevUtils
|
9
|
+
module Ppt
|
10
|
+
# Class for working with Puppet Modules
|
11
|
+
class PuppetModule
|
12
|
+
DEF_FILES = {
|
13
|
+
metadata: 'metadata.json',
|
14
|
+
readme: 'README.md',
|
15
|
+
reference: 'REFERENCE.md',
|
16
|
+
changelog: 'CHANGELOG.md',
|
17
|
+
fixtures: '.fixtures.yml',
|
18
|
+
rubocop: '.rubocop.yml',
|
19
|
+
sync: '.sync.yml',
|
20
|
+
pdkignore: '.pdkignore',
|
21
|
+
gitignore: '.gitignore'
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
attr_reader :directory, :special_files
|
25
|
+
|
26
|
+
def initialize(directory = Dir.pwd)
|
27
|
+
AbideDevUtils::Validate.directory(directory)
|
28
|
+
@directory = directory
|
29
|
+
@special_files = DEF_FILES.dup.transform_values { |v| File.expand_path(File.join(@directory, v)) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def name(strip_namespace: false)
|
33
|
+
strip_namespace ? metadata['name'].split('-')[-1] : metadata['name']
|
34
|
+
end
|
35
|
+
|
36
|
+
def metadata
|
37
|
+
@metadata ||= JSON.parse(File.read(special_files[:metadata]))
|
38
|
+
end
|
39
|
+
|
40
|
+
def supported_os
|
41
|
+
@supported_os ||= find_supported_os
|
42
|
+
end
|
43
|
+
|
44
|
+
def hiera_conf
|
45
|
+
@hiera_conf ||= AbideDevUtils::Ppt::Hiera::Config.new
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def find_supported_os
|
51
|
+
return [] unless metadata['operatingsystem_support']
|
52
|
+
|
53
|
+
metadata['operatingsystem_support'].each_with_object([]) do |os, arr|
|
54
|
+
os['operatingsystemrelease'].each do |r|
|
55
|
+
arr << "#{os['operatingsystem']}::#{r}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def in_dir
|
61
|
+
return unless block_given?
|
62
|
+
|
63
|
+
current = Dir.pwd
|
64
|
+
if current == File.expand_path(directory)
|
65
|
+
yield
|
66
|
+
else
|
67
|
+
Dir.chdir(directory)
|
68
|
+
yield
|
69
|
+
Dir.chdir(current)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/abide_dev_utils/ppt.rb
CHANGED
@@ -4,6 +4,9 @@ require 'abide_dev_utils/output'
|
|
4
4
|
require 'abide_dev_utils/validate'
|
5
5
|
require 'abide_dev_utils/errors'
|
6
6
|
require 'abide_dev_utils/ppt/class_utils'
|
7
|
+
require 'abide_dev_utils/ppt/facter_utils'
|
8
|
+
require 'abide_dev_utils/ppt/hiera'
|
9
|
+
require 'abide_dev_utils/ppt/puppet_module'
|
7
10
|
|
8
11
|
module AbideDevUtils
|
9
12
|
module Ppt
|
@@ -63,11 +66,6 @@ module AbideDevUtils
|
|
63
66
|
AbideDevUtils::Output.simple('Successfully fixed all classes.')
|
64
67
|
end
|
65
68
|
|
66
|
-
def self.generate_coverage_report(puppet_class_dir, hiera_path, profile = nil)
|
67
|
-
require 'abide_dev_utils/ppt/coverage'
|
68
|
-
CoverageReport.generate(puppet_class_dir, hiera_path, profile)
|
69
|
-
end
|
70
|
-
|
71
69
|
def self.build_new_object(type, name, opts)
|
72
70
|
require 'abide_dev_utils/ppt/new_obj'
|
73
71
|
AbideDevUtils::Ppt::NewObjectBuilder.new(
|
@@ -3,7 +3,12 @@
|
|
3
3
|
require 'abide_dev_utils/errors'
|
4
4
|
|
5
5
|
module AbideDevUtils
|
6
|
+
# Methods used for validating data
|
6
7
|
module Validate
|
8
|
+
def self.puppet_module_directory(path = Dir.pwd)
|
9
|
+
raise AbideDevUtils::Errors::Ppt::NotModuleDirError, path unless File.file?(File.join(path, 'metadata.json'))
|
10
|
+
end
|
11
|
+
|
7
12
|
def self.filesystem_path(path)
|
8
13
|
raise AbideDevUtils::Errors::FileNotFoundError, path unless File.exist?(path)
|
9
14
|
end
|
@@ -22,6 +27,15 @@ module AbideDevUtils
|
|
22
27
|
raise AbideDevUtils::Errors::PathNotDirectoryError, path unless File.directory?(path)
|
23
28
|
end
|
24
29
|
|
30
|
+
def self.populated_string(thing)
|
31
|
+
raise AbideDevUtils::Errors::NotPopulatedStringError, 'Object is nil' if thing.nil?
|
32
|
+
|
33
|
+
unless thing.instance_of?(String)
|
34
|
+
raise AbideDevUtils::Errors::NotPopulatedStringError, "Object is not a String. Type: #{thing.class}"
|
35
|
+
end
|
36
|
+
raise AbideDevUtils::Errors::NotPopulatedStringError, 'String is empty' if thing.empty?
|
37
|
+
end
|
38
|
+
|
25
39
|
def self.not_empty(thing, msg)
|
26
40
|
raise AbideDevUtils::Errors::ObjectEmptyError, msg if thing.empty?
|
27
41
|
end
|