pdk-akerl 1.8.0.1
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 +7 -0
- data/CHANGELOG.md +826 -0
- data/LICENSE +201 -0
- data/README.md +133 -0
- data/exe/pdk +10 -0
- data/lib/pdk.rb +10 -0
- data/lib/pdk/answer_file.rb +121 -0
- data/lib/pdk/cli.rb +113 -0
- data/lib/pdk/cli/build.rb +76 -0
- data/lib/pdk/cli/bundle.rb +42 -0
- data/lib/pdk/cli/convert.rb +41 -0
- data/lib/pdk/cli/errors.rb +23 -0
- data/lib/pdk/cli/exec.rb +246 -0
- data/lib/pdk/cli/exec_group.rb +67 -0
- data/lib/pdk/cli/module.rb +14 -0
- data/lib/pdk/cli/module/build.rb +14 -0
- data/lib/pdk/cli/module/generate.rb +45 -0
- data/lib/pdk/cli/new.rb +17 -0
- data/lib/pdk/cli/new/class.rb +32 -0
- data/lib/pdk/cli/new/defined_type.rb +30 -0
- data/lib/pdk/cli/new/module.rb +41 -0
- data/lib/pdk/cli/new/provider.rb +27 -0
- data/lib/pdk/cli/new/task.rb +31 -0
- data/lib/pdk/cli/test.rb +12 -0
- data/lib/pdk/cli/test/unit.rb +88 -0
- data/lib/pdk/cli/update.rb +32 -0
- data/lib/pdk/cli/util.rb +193 -0
- data/lib/pdk/cli/util/command_redirector.rb +26 -0
- data/lib/pdk/cli/util/interview.rb +63 -0
- data/lib/pdk/cli/util/option_normalizer.rb +53 -0
- data/lib/pdk/cli/util/option_validator.rb +56 -0
- data/lib/pdk/cli/validate.rb +124 -0
- data/lib/pdk/generate.rb +11 -0
- data/lib/pdk/generate/defined_type.rb +49 -0
- data/lib/pdk/generate/module.rb +318 -0
- data/lib/pdk/generate/provider.rb +82 -0
- data/lib/pdk/generate/puppet_class.rb +48 -0
- data/lib/pdk/generate/puppet_object.rb +288 -0
- data/lib/pdk/generate/task.rb +86 -0
- data/lib/pdk/i18n.rb +4 -0
- data/lib/pdk/logger.rb +28 -0
- data/lib/pdk/module.rb +21 -0
- data/lib/pdk/module/build.rb +214 -0
- data/lib/pdk/module/convert.rb +209 -0
- data/lib/pdk/module/metadata.rb +193 -0
- data/lib/pdk/module/templatedir.rb +313 -0
- data/lib/pdk/module/update.rb +111 -0
- data/lib/pdk/module/update_manager.rb +210 -0
- data/lib/pdk/report.rb +112 -0
- data/lib/pdk/report/event.rb +357 -0
- data/lib/pdk/template_file.rb +89 -0
- data/lib/pdk/tests/unit.rb +213 -0
- data/lib/pdk/util.rb +271 -0
- data/lib/pdk/util/bundler.rb +253 -0
- data/lib/pdk/util/filesystem.rb +12 -0
- data/lib/pdk/util/git.rb +74 -0
- data/lib/pdk/util/puppet_version.rb +242 -0
- data/lib/pdk/util/ruby_version.rb +147 -0
- data/lib/pdk/util/vendored_file.rb +88 -0
- data/lib/pdk/util/version.rb +42 -0
- data/lib/pdk/util/windows.rb +13 -0
- data/lib/pdk/util/windows/api_types.rb +57 -0
- data/lib/pdk/util/windows/file.rb +36 -0
- data/lib/pdk/util/windows/string.rb +16 -0
- data/lib/pdk/validate.rb +14 -0
- data/lib/pdk/validate/base_validator.rb +209 -0
- data/lib/pdk/validate/metadata/metadata_json_lint.rb +86 -0
- data/lib/pdk/validate/metadata/metadata_syntax.rb +109 -0
- data/lib/pdk/validate/metadata_validator.rb +30 -0
- data/lib/pdk/validate/puppet/puppet_lint.rb +67 -0
- data/lib/pdk/validate/puppet/puppet_syntax.rb +112 -0
- data/lib/pdk/validate/puppet_validator.rb +30 -0
- data/lib/pdk/validate/ruby/rubocop.rb +77 -0
- data/lib/pdk/validate/ruby_validator.rb +29 -0
- data/lib/pdk/validate/tasks/metadata_lint.rb +126 -0
- data/lib/pdk/validate/tasks/name.rb +88 -0
- data/lib/pdk/validate/tasks_validator.rb +33 -0
- data/lib/pdk/version.rb +4 -0
- data/locales/config.yaml +21 -0
- data/locales/pdk.pot +1283 -0
- metadata +304 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'pdk/util'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module Util
|
5
|
+
class RubyVersion
|
6
|
+
class << self
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :instance, :gem_path, :gem_paths_raw, :gem_home, :available_puppet_versions, :bin_path
|
10
|
+
|
11
|
+
attr_reader :instance
|
12
|
+
|
13
|
+
def instance(version = nil)
|
14
|
+
use(version) unless version.nil?
|
15
|
+
|
16
|
+
if @instance.nil?
|
17
|
+
@instance = {}
|
18
|
+
@instance.default_proc = proc do |hash, key|
|
19
|
+
hash[key] = new(key)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@instance[active_ruby_version]
|
23
|
+
end
|
24
|
+
|
25
|
+
def active_ruby_version
|
26
|
+
@active_ruby_version || default_ruby_version
|
27
|
+
end
|
28
|
+
|
29
|
+
def use(version)
|
30
|
+
if versions.key?(version)
|
31
|
+
@active_ruby_version = version
|
32
|
+
else
|
33
|
+
raise ArgumentError, _('Unknown Ruby version "%{ruby_version}"') % {
|
34
|
+
ruby_version: version,
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def scan_for_packaged_rubies
|
40
|
+
ruby_basedir = File.join(PDK::Util.pdk_package_basedir, 'private', 'ruby', '*')
|
41
|
+
Dir[ruby_basedir].sort.map { |ruby_dir|
|
42
|
+
version = File.basename(ruby_dir)
|
43
|
+
[version, version.split('.').take(2).concat(['0']).join('.')]
|
44
|
+
}.reverse.to_h
|
45
|
+
end
|
46
|
+
|
47
|
+
def default_ruby_version
|
48
|
+
# For now, the packaged versions will be using default of 2.4.4.
|
49
|
+
return '2.4.4' if PDK::Util.package_install?
|
50
|
+
|
51
|
+
# TODO: may not be a safe assumption that highest available version should be default
|
52
|
+
latest_ruby_version
|
53
|
+
end
|
54
|
+
|
55
|
+
def latest_ruby_version
|
56
|
+
versions.keys.sort { |a, b| Gem::Version.new(b) <=> Gem::Version.new(a) }.first
|
57
|
+
end
|
58
|
+
|
59
|
+
def versions
|
60
|
+
@versions ||= if PDK::Util.package_install?
|
61
|
+
scan_for_packaged_rubies
|
62
|
+
else
|
63
|
+
{ RbConfig::CONFIG['RUBY_PROGRAM_VERSION'] => RbConfig::CONFIG['ruby_version'] }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
attr_reader :ruby_version
|
69
|
+
|
70
|
+
def initialize(ruby_version = nil)
|
71
|
+
@ruby_version = ruby_version || default_ruby_version
|
72
|
+
end
|
73
|
+
|
74
|
+
def bin_path
|
75
|
+
if PDK::Util.package_install?
|
76
|
+
File.join(PDK::Util.pdk_package_basedir, 'private', 'ruby', ruby_version, 'bin')
|
77
|
+
else
|
78
|
+
RbConfig::CONFIG['bindir']
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def gem_paths_raw
|
83
|
+
if PDK::Util.package_install?
|
84
|
+
# Subprocesses use their own set of gems which are managed by pdk or
|
85
|
+
# installed with the package. We also include the separate gem path
|
86
|
+
# where our packaged multi-puppet installations live.
|
87
|
+
[
|
88
|
+
File.join(PDK::Util.pdk_package_basedir, 'private', 'ruby', ruby_version, 'lib', 'ruby', 'gems', versions[ruby_version]),
|
89
|
+
File.join(PDK::Util.package_cachedir, 'ruby', versions[ruby_version]),
|
90
|
+
File.join(PDK::Util.pdk_package_basedir, 'private', 'puppet', 'ruby', versions[ruby_version]),
|
91
|
+
]
|
92
|
+
else
|
93
|
+
# This allows the subprocess to find the 'bundler' gem, which isn't
|
94
|
+
# in GEM_HOME for gem installs.
|
95
|
+
# TODO: There must be a better way to do this than shelling out to
|
96
|
+
# gem... Perhaps can be replaced with "Gem.path"?
|
97
|
+
[File.absolute_path(File.join(`gem which bundler`, '..', '..', '..', '..'))]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def gem_path
|
102
|
+
gem_paths_raw.join(File::PATH_SEPARATOR)
|
103
|
+
end
|
104
|
+
|
105
|
+
def gem_home
|
106
|
+
# `bundle install --path` ignores all "system" installed gems and
|
107
|
+
# causes unnecessary package installs. `bundle install` (without
|
108
|
+
# --path) installs into GEM_HOME, which by default is non-user
|
109
|
+
# writeable.
|
110
|
+
# To still use the pre-installed packages, but allow folks to install
|
111
|
+
# additional gems, we set GEM_HOME to the user's cachedir and put all
|
112
|
+
# other cache locations onto GEM_PATH.
|
113
|
+
# See https://stackoverflow.com/a/11277228 for background
|
114
|
+
File.join(PDK::Util.cachedir, 'ruby', versions[ruby_version])
|
115
|
+
end
|
116
|
+
|
117
|
+
def available_puppet_versions
|
118
|
+
return @available_puppet_versions unless @available_puppet_versions.nil?
|
119
|
+
|
120
|
+
puppet_spec_files = Dir[File.join(gem_home, 'specifications', '**', 'puppet*.gemspec')]
|
121
|
+
|
122
|
+
gem_path.split(File::PATH_SEPARATOR).each do |path|
|
123
|
+
puppet_spec_files += Dir[File.join(path, 'specifications', '**', 'puppet*.gemspec')]
|
124
|
+
end
|
125
|
+
|
126
|
+
puppet_specs = []
|
127
|
+
|
128
|
+
puppet_spec_files.each do |specfile|
|
129
|
+
spec = Gem::Specification.load(specfile)
|
130
|
+
puppet_specs << spec if spec.name == 'puppet'
|
131
|
+
end
|
132
|
+
|
133
|
+
@available_puppet_versions = puppet_specs.map(&:version).sort { |a, b| b <=> a }
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def default_ruby_version
|
139
|
+
self.class.default_ruby_version
|
140
|
+
end
|
141
|
+
|
142
|
+
def versions
|
143
|
+
self.class.versions
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'pdk/util'
|
2
|
+
require 'net/https'
|
3
|
+
require 'openssl'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'pdk/util/filesystem'
|
6
|
+
|
7
|
+
module PDK
|
8
|
+
module Util
|
9
|
+
class VendoredFile
|
10
|
+
class DownloadError < StandardError; end
|
11
|
+
|
12
|
+
HTTP_ERRORS = [
|
13
|
+
EOFError,
|
14
|
+
Errno::ECONNRESET,
|
15
|
+
Errno::EINVAL,
|
16
|
+
Errno::ECONNREFUSED,
|
17
|
+
Net::HTTPBadResponse,
|
18
|
+
Net::HTTPHeaderSyntaxError,
|
19
|
+
Net::ProtocolError,
|
20
|
+
Timeout::Error,
|
21
|
+
].freeze
|
22
|
+
|
23
|
+
attr_reader :file_name
|
24
|
+
attr_reader :url
|
25
|
+
|
26
|
+
include PDK::Util::Filesystem
|
27
|
+
|
28
|
+
def initialize(file_name, url)
|
29
|
+
@file_name = file_name
|
30
|
+
@url = url
|
31
|
+
end
|
32
|
+
|
33
|
+
def read
|
34
|
+
return File.read(package_vendored_path) if PDK::Util.package_install?
|
35
|
+
return File.read(gem_vendored_path) if File.file?(gem_vendored_path)
|
36
|
+
|
37
|
+
content = download_file
|
38
|
+
|
39
|
+
# TODO: should only write if it's valid JSON
|
40
|
+
# TODO: need a way to invalidate if out of date
|
41
|
+
FileUtils.mkdir_p(File.dirname(gem_vendored_path))
|
42
|
+
write_file(gem_vendored_path, content)
|
43
|
+
content
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def download_file
|
49
|
+
PDK.logger.debug _('%{file_name} was not found in the cache, downloading it from %{url}.') % {
|
50
|
+
file_name: file_name,
|
51
|
+
url: url,
|
52
|
+
}
|
53
|
+
|
54
|
+
uri = URI.parse(url)
|
55
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
56
|
+
http.use_ssl = true
|
57
|
+
# TODO: Get rid of this, possible workaround:
|
58
|
+
# https://github.com/glennsarti/dev-tools/blob/master/RubyCerts.ps1
|
59
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if Gem.win_platform?
|
60
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
61
|
+
response = http.request(request)
|
62
|
+
|
63
|
+
unless response.code == '200'
|
64
|
+
raise DownloadError, _('Unable to download %{url}. %{code}: %{message}.') % {
|
65
|
+
url: url,
|
66
|
+
code: response.code,
|
67
|
+
message: response.message,
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
response.body
|
72
|
+
rescue *HTTP_ERRORS => e
|
73
|
+
raise DownloadError, _('Unable to download %{url}. Check internet connectivity and try again. %{error}') % {
|
74
|
+
url: url,
|
75
|
+
error: e,
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def package_vendored_path
|
80
|
+
@package_vendored_path ||= File.join(PDK::Util.package_cachedir, file_name)
|
81
|
+
end
|
82
|
+
|
83
|
+
def gem_vendored_path
|
84
|
+
@gem_vendored_path ||= File.join(PDK::Util.cachedir, PDK::VERSION, file_name)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'pdk/version'
|
2
|
+
require 'pdk/cli/exec'
|
3
|
+
require 'pdk/util/git'
|
4
|
+
require 'pdk/logger'
|
5
|
+
|
6
|
+
module PDK
|
7
|
+
module Util
|
8
|
+
module Version
|
9
|
+
def self.version_string
|
10
|
+
"#{PDK::VERSION} #{pdk_ref}".strip.freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.pdk_ref
|
14
|
+
ref = "#{pkg_sha} #{git_ref}".strip
|
15
|
+
ref.empty? ? nil : "(#{ref})"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.pkg_sha
|
19
|
+
if version_file && File.exist?(version_file)
|
20
|
+
ver = File.read(version_file)
|
21
|
+
sha = ver.strip.split('.')[5] unless ver.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
sha
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.git_ref
|
28
|
+
source_git_dir = File.join(File.expand_path('../../..', File.dirname(__FILE__)), '.git')
|
29
|
+
|
30
|
+
return nil unless File.directory?(source_git_dir)
|
31
|
+
|
32
|
+
ref_result = PDK::Util::Git.git('--git-dir', source_git_dir, 'describe', '--all', '--long')
|
33
|
+
return ref_result[:stdout].strip if ref_result[:exit_code].zero?
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.version_file
|
37
|
+
# FIXME: this gets called a LOT and doesn't currently get cached
|
38
|
+
PDK::Util.find_upwards('PDK_VERSION', File.dirname(__FILE__))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'pdk/util/windows/string'
|
3
|
+
|
4
|
+
module PDK::Util::Windows::APITypes
|
5
|
+
module ::FFI
|
6
|
+
WIN32_FALSE = 0
|
7
|
+
|
8
|
+
# standard Win32 error codes
|
9
|
+
ERROR_SUCCESS = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
class ::FFI::Pointer
|
13
|
+
def self.from_string_to_wide_string(str, &_block)
|
14
|
+
str = PDK::Util::Windows::String.wide_string(str)
|
15
|
+
FFI::MemoryPointer.new(:byte, str.bytesize) do |ptr|
|
16
|
+
# uchar here is synonymous with byte
|
17
|
+
ptr.put_array_of_uchar(0, str.bytes.to_a)
|
18
|
+
|
19
|
+
yield ptr
|
20
|
+
end
|
21
|
+
|
22
|
+
# ptr has already had free called, so nothing to return
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def read_wide_string(char_length, dst_encoding = Encoding::UTF_8, encode_options = {})
|
27
|
+
# char_length is number of wide chars (typically excluding NULLs), *not* bytes
|
28
|
+
str = get_bytes(0, char_length * 2).force_encoding('UTF-16LE')
|
29
|
+
str.encode(dst_encoding, str.encoding, encode_options)
|
30
|
+
rescue StandardError => e
|
31
|
+
PDK.logger.debug _('Unable to convert value %{string} to encoding %{encoding} due to %{error}') % {
|
32
|
+
string: str.dump,
|
33
|
+
encoding: dst_encoding,
|
34
|
+
error: e.inspect,
|
35
|
+
}
|
36
|
+
raise
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# FFI Types
|
41
|
+
# https://github.com/ffi/ffi/wiki/Types
|
42
|
+
|
43
|
+
# Windows - Common Data Types
|
44
|
+
# https://msdn.microsoft.com/en-us/library/cc230309.aspx
|
45
|
+
|
46
|
+
# Windows Data Types
|
47
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
|
48
|
+
|
49
|
+
FFI.typedef :uint32, :dword
|
50
|
+
# buffer_inout is similar to pointer (platform specific), but optimized for buffers
|
51
|
+
FFI.typedef :buffer_inout, :lpwstr
|
52
|
+
# buffer_in is similar to pointer (platform specific), but optimized for CONST read only buffers
|
53
|
+
FFI.typedef :buffer_in, :lpcwstr
|
54
|
+
# 8 bits per byte
|
55
|
+
FFI.typedef :uchar, :byte
|
56
|
+
FFI.typedef :uint16, :wchar
|
57
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'pdk/util/windows'
|
2
|
+
|
3
|
+
module PDK::Util::Windows::File
|
4
|
+
require 'ffi'
|
5
|
+
extend FFI::Library
|
6
|
+
extend PDK::Util::Windows::String
|
7
|
+
|
8
|
+
def get_long_pathname(path)
|
9
|
+
converted = ''
|
10
|
+
FFI::Pointer.from_string_to_wide_string(path) do |path_ptr|
|
11
|
+
# includes terminating NULL
|
12
|
+
buffer_size = GetLongPathNameW(path_ptr, FFI::Pointer::NULL, 0)
|
13
|
+
FFI::MemoryPointer.new(:wchar, buffer_size) do |converted_ptr|
|
14
|
+
if GetLongPathNameW(path_ptr, converted_ptr, buffer_size) == FFI::WIN32_FALSE
|
15
|
+
raise _('Failed to call GetLongPathName')
|
16
|
+
end
|
17
|
+
|
18
|
+
converted = converted_ptr.read_wide_string(buffer_size - 1)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
converted
|
23
|
+
end
|
24
|
+
module_function :get_long_pathname
|
25
|
+
|
26
|
+
ffi_convention :stdcall
|
27
|
+
|
28
|
+
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa364980(v=vs.85).aspx
|
29
|
+
# DWORD WINAPI GetLongPathName(
|
30
|
+
# _In_ LPCTSTR lpszShortPath,
|
31
|
+
# _Out_ LPTSTR lpszLongPath,
|
32
|
+
# _In_ DWORD cchBuffer
|
33
|
+
# );
|
34
|
+
ffi_lib :kernel32
|
35
|
+
attach_function :GetLongPathNameW, [:lpcwstr, :lpwstr, :dword], :dword
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'pdk/util/windows'
|
2
|
+
|
3
|
+
module PDK::Util::Windows::String
|
4
|
+
def wide_string(str)
|
5
|
+
# if given a nil string, assume caller wants to pass a nil pointer to win32
|
6
|
+
return nil if str.nil?
|
7
|
+
# ruby (< 2.1) does not respect multibyte terminators, so it is possible
|
8
|
+
# for a string to contain a single trailing null byte, followed by garbage
|
9
|
+
# causing buffer overruns.
|
10
|
+
#
|
11
|
+
# See http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?revision=41920&view=revision
|
12
|
+
newstr = str + "\0".encode(str.encoding)
|
13
|
+
newstr.encode!('UTF-16LE')
|
14
|
+
end
|
15
|
+
module_function :wide_string
|
16
|
+
end
|
data/lib/pdk/validate.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'pdk/validate/metadata_validator'
|
2
|
+
require 'pdk/validate/puppet_validator'
|
3
|
+
require 'pdk/validate/ruby_validator'
|
4
|
+
require 'pdk/validate/tasks_validator'
|
5
|
+
|
6
|
+
module PDK
|
7
|
+
module Validate
|
8
|
+
def self.validators
|
9
|
+
@validators ||= [MetadataValidator, PuppetValidator, RubyValidator, TasksValidator].freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
class ParseOutputError < StandardError; end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
require 'pdk'
|
2
|
+
require 'pdk/cli/exec'
|
3
|
+
require 'pdk/module'
|
4
|
+
|
5
|
+
module PDK
|
6
|
+
module Validate
|
7
|
+
class BaseValidator
|
8
|
+
# Controls how many times the validator is invoked.
|
9
|
+
#
|
10
|
+
# :once - The validator will be invoked once and passed all the
|
11
|
+
# targets.
|
12
|
+
# :per_target - The validator will be invoked for each target
|
13
|
+
# separately.
|
14
|
+
INVOKE_STYLE = :once
|
15
|
+
|
16
|
+
# Controls how the validator behaves if not passed any targets.
|
17
|
+
#
|
18
|
+
# true - PDK will not pass the globbed targets to the validator command
|
19
|
+
# and it will instead rely on the underlying tool to find its
|
20
|
+
# own default targets.
|
21
|
+
# false - PDK will pass the globbed targets to the validator command.
|
22
|
+
ALLOW_EMPTY_TARGETS = false
|
23
|
+
|
24
|
+
def self.cmd_path
|
25
|
+
File.join(PDK::Util.module_root, 'bin', cmd)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Parses the target strings provided from the CLI
|
29
|
+
#
|
30
|
+
# @param options [Hash] A Hash containing the input options from the CLI.
|
31
|
+
#
|
32
|
+
# @return targets [Array] An Array of Strings containing target file paths
|
33
|
+
# for the validator to validate.
|
34
|
+
# @return skipped [Array] An Array of Strings containing targets
|
35
|
+
# that are skipped due to target not containing
|
36
|
+
# any files that can be validated by the validator.
|
37
|
+
# @return invalid [Array] An Array of Strings containing targets that do
|
38
|
+
# not exist, and will not be run by validator.
|
39
|
+
def self.parse_targets(options)
|
40
|
+
# If no targets are specified, then we will run validations from the
|
41
|
+
# base module directory.
|
42
|
+
|
43
|
+
targets = options.fetch(:targets, []).empty? ? [PDK::Util.module_root] : options[:targets]
|
44
|
+
|
45
|
+
targets.map! { |r| r.gsub(File::ALT_SEPARATOR, File::SEPARATOR) } if File::ALT_SEPARATOR
|
46
|
+
skipped = []
|
47
|
+
invalid = []
|
48
|
+
matched = targets.map { |target|
|
49
|
+
if respond_to?(:pattern)
|
50
|
+
if File.directory?(target)
|
51
|
+
target_root = PDK::Util.module_root
|
52
|
+
pattern_glob = Array(pattern).map { |p| Dir.glob(File.join(target_root, p)) }
|
53
|
+
|
54
|
+
target_list = pattern_glob.flatten.map do |file|
|
55
|
+
if File.fnmatch(File.join(File.expand_path(target), '*'), file)
|
56
|
+
Pathname.new(file).relative_path_from(Pathname.new(PDK::Util.module_root)).to_s
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
ignore_list = ignore_pathspec
|
61
|
+
target_list = target_list.reject { |file| ignore_list.match(file) }
|
62
|
+
|
63
|
+
skipped << target if target_list.flatten.empty?
|
64
|
+
target_list
|
65
|
+
elsif File.file?(target)
|
66
|
+
if Array(pattern).include? target
|
67
|
+
target
|
68
|
+
elsif Array(pattern).any? { |p| File.fnmatch(File.expand_path(p), File.expand_path(target)) }
|
69
|
+
target
|
70
|
+
else
|
71
|
+
skipped << target
|
72
|
+
next
|
73
|
+
end
|
74
|
+
else
|
75
|
+
invalid << target
|
76
|
+
next
|
77
|
+
end
|
78
|
+
else
|
79
|
+
target
|
80
|
+
end
|
81
|
+
}.compact.flatten
|
82
|
+
[matched, skipped, invalid]
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.ignore_pathspec
|
86
|
+
ignore_pathspec = PDK::Module.default_ignored_pathspec.dup
|
87
|
+
|
88
|
+
if respond_to?(:pattern_ignore)
|
89
|
+
Array(pattern_ignore).each do |pattern|
|
90
|
+
ignore_pathspec.add(pattern)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
ignore_pathspec
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.parse_options(_options, targets)
|
98
|
+
targets
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.spinner_text(_targets = nil)
|
102
|
+
_('Invoking %{cmd}') % { cmd: cmd }
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.process_skipped(report, skipped = [])
|
106
|
+
skipped.each do |skipped_target|
|
107
|
+
PDK.logger.debug(_('%{validator}: Skipped \'%{target}\'. Target does not contain any files to validate (%{pattern}).') % { validator: name, target: skipped_target, pattern: pattern })
|
108
|
+
report.add_event(
|
109
|
+
file: skipped_target,
|
110
|
+
source: name,
|
111
|
+
message: _('Target does not contain any files to validate (%{pattern}).') % { pattern: pattern },
|
112
|
+
severity: :info,
|
113
|
+
state: :skipped,
|
114
|
+
)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.process_invalid(report, invalid = [])
|
119
|
+
invalid.each do |invalid_target|
|
120
|
+
PDK.logger.debug(_('%{validator}: Skipped \'%{target}\'. Target file not found.') % { validator: name, target: invalid_target })
|
121
|
+
report.add_event(
|
122
|
+
file: invalid_target,
|
123
|
+
source: name,
|
124
|
+
message: _('File does not exist.'),
|
125
|
+
severity: :error,
|
126
|
+
state: :error,
|
127
|
+
)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.allow_empty_targets?
|
132
|
+
self::ALLOW_EMPTY_TARGETS == true
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.invoke(report, options = {})
|
136
|
+
targets, skipped, invalid = parse_targets(options)
|
137
|
+
|
138
|
+
process_skipped(report, skipped)
|
139
|
+
process_invalid(report, invalid)
|
140
|
+
|
141
|
+
return 0 if targets.empty?
|
142
|
+
|
143
|
+
PDK::Util::Bundler.ensure_binstubs!(cmd)
|
144
|
+
|
145
|
+
# If invoking :per_target, split the targets array into an array of
|
146
|
+
# single element arrays (one per target). If invoking :once, wrap the
|
147
|
+
# targets array in another array. This is so we can loop through the
|
148
|
+
# invokes with the same logic, regardless of which invoke style is
|
149
|
+
# needed.
|
150
|
+
#
|
151
|
+
if self::INVOKE_STYLE == :per_target
|
152
|
+
targets = targets.combination(1).to_a
|
153
|
+
else
|
154
|
+
targets = targets.each_slice(1000).to_a
|
155
|
+
options[:split_exec] = PDK::CLI::ExecGroup.new(spinner_text(targets), parallel: false)
|
156
|
+
end
|
157
|
+
|
158
|
+
if options.fetch(:targets, []).empty? && allow_empty_targets?
|
159
|
+
targets = [[]]
|
160
|
+
end
|
161
|
+
|
162
|
+
exit_codes = []
|
163
|
+
|
164
|
+
targets.each do |invokation_targets|
|
165
|
+
cmd_argv = parse_options(options, invokation_targets).unshift(cmd_path).compact
|
166
|
+
cmd_argv.unshift(File.join(PDK::Util::RubyVersion.bin_path, 'ruby.exe'), '-W0') if Gem.win_platform?
|
167
|
+
|
168
|
+
command = PDK::CLI::Exec::Command.new(*cmd_argv).tap do |c|
|
169
|
+
c.context = :module
|
170
|
+
c.environment = { 'PUPPET_GEM_VERSION' => options[:puppet] } if options[:puppet]
|
171
|
+
unless options[:split_exec]
|
172
|
+
exec_group = options[:exec_group]
|
173
|
+
if exec_group
|
174
|
+
sub_spinner = exec_group.add_spinner(spinner_text(invokation_targets))
|
175
|
+
c.register_spinner(sub_spinner)
|
176
|
+
else
|
177
|
+
c.add_spinner(spinner_text(invokation_targets))
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
if options[:split_exec]
|
183
|
+
options[:split_exec].register do
|
184
|
+
result = command.execute!
|
185
|
+
|
186
|
+
begin
|
187
|
+
parse_output(report, result, invokation_targets.compact)
|
188
|
+
rescue PDK::Validate::ParseOutputError => e
|
189
|
+
$stderr.puts e.message
|
190
|
+
end
|
191
|
+
result[:exit_code]
|
192
|
+
end
|
193
|
+
else
|
194
|
+
result = command.execute!
|
195
|
+
exit_codes << result[:exit_code]
|
196
|
+
|
197
|
+
begin
|
198
|
+
parse_output(report, result, invokation_targets.compact)
|
199
|
+
rescue PDK::Validate::ParseOutputError => e
|
200
|
+
$stderr.puts e.message
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
options.key?(:split_exec) ? options[:split_exec].exit_code : exit_codes.max
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|