abide_dev_utils 0.9.7 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|