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.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +826 -0
  3. data/LICENSE +201 -0
  4. data/README.md +133 -0
  5. data/exe/pdk +10 -0
  6. data/lib/pdk.rb +10 -0
  7. data/lib/pdk/answer_file.rb +121 -0
  8. data/lib/pdk/cli.rb +113 -0
  9. data/lib/pdk/cli/build.rb +76 -0
  10. data/lib/pdk/cli/bundle.rb +42 -0
  11. data/lib/pdk/cli/convert.rb +41 -0
  12. data/lib/pdk/cli/errors.rb +23 -0
  13. data/lib/pdk/cli/exec.rb +246 -0
  14. data/lib/pdk/cli/exec_group.rb +67 -0
  15. data/lib/pdk/cli/module.rb +14 -0
  16. data/lib/pdk/cli/module/build.rb +14 -0
  17. data/lib/pdk/cli/module/generate.rb +45 -0
  18. data/lib/pdk/cli/new.rb +17 -0
  19. data/lib/pdk/cli/new/class.rb +32 -0
  20. data/lib/pdk/cli/new/defined_type.rb +30 -0
  21. data/lib/pdk/cli/new/module.rb +41 -0
  22. data/lib/pdk/cli/new/provider.rb +27 -0
  23. data/lib/pdk/cli/new/task.rb +31 -0
  24. data/lib/pdk/cli/test.rb +12 -0
  25. data/lib/pdk/cli/test/unit.rb +88 -0
  26. data/lib/pdk/cli/update.rb +32 -0
  27. data/lib/pdk/cli/util.rb +193 -0
  28. data/lib/pdk/cli/util/command_redirector.rb +26 -0
  29. data/lib/pdk/cli/util/interview.rb +63 -0
  30. data/lib/pdk/cli/util/option_normalizer.rb +53 -0
  31. data/lib/pdk/cli/util/option_validator.rb +56 -0
  32. data/lib/pdk/cli/validate.rb +124 -0
  33. data/lib/pdk/generate.rb +11 -0
  34. data/lib/pdk/generate/defined_type.rb +49 -0
  35. data/lib/pdk/generate/module.rb +318 -0
  36. data/lib/pdk/generate/provider.rb +82 -0
  37. data/lib/pdk/generate/puppet_class.rb +48 -0
  38. data/lib/pdk/generate/puppet_object.rb +288 -0
  39. data/lib/pdk/generate/task.rb +86 -0
  40. data/lib/pdk/i18n.rb +4 -0
  41. data/lib/pdk/logger.rb +28 -0
  42. data/lib/pdk/module.rb +21 -0
  43. data/lib/pdk/module/build.rb +214 -0
  44. data/lib/pdk/module/convert.rb +209 -0
  45. data/lib/pdk/module/metadata.rb +193 -0
  46. data/lib/pdk/module/templatedir.rb +313 -0
  47. data/lib/pdk/module/update.rb +111 -0
  48. data/lib/pdk/module/update_manager.rb +210 -0
  49. data/lib/pdk/report.rb +112 -0
  50. data/lib/pdk/report/event.rb +357 -0
  51. data/lib/pdk/template_file.rb +89 -0
  52. data/lib/pdk/tests/unit.rb +213 -0
  53. data/lib/pdk/util.rb +271 -0
  54. data/lib/pdk/util/bundler.rb +253 -0
  55. data/lib/pdk/util/filesystem.rb +12 -0
  56. data/lib/pdk/util/git.rb +74 -0
  57. data/lib/pdk/util/puppet_version.rb +242 -0
  58. data/lib/pdk/util/ruby_version.rb +147 -0
  59. data/lib/pdk/util/vendored_file.rb +88 -0
  60. data/lib/pdk/util/version.rb +42 -0
  61. data/lib/pdk/util/windows.rb +13 -0
  62. data/lib/pdk/util/windows/api_types.rb +57 -0
  63. data/lib/pdk/util/windows/file.rb +36 -0
  64. data/lib/pdk/util/windows/string.rb +16 -0
  65. data/lib/pdk/validate.rb +14 -0
  66. data/lib/pdk/validate/base_validator.rb +209 -0
  67. data/lib/pdk/validate/metadata/metadata_json_lint.rb +86 -0
  68. data/lib/pdk/validate/metadata/metadata_syntax.rb +109 -0
  69. data/lib/pdk/validate/metadata_validator.rb +30 -0
  70. data/lib/pdk/validate/puppet/puppet_lint.rb +67 -0
  71. data/lib/pdk/validate/puppet/puppet_syntax.rb +112 -0
  72. data/lib/pdk/validate/puppet_validator.rb +30 -0
  73. data/lib/pdk/validate/ruby/rubocop.rb +77 -0
  74. data/lib/pdk/validate/ruby_validator.rb +29 -0
  75. data/lib/pdk/validate/tasks/metadata_lint.rb +126 -0
  76. data/lib/pdk/validate/tasks/name.rb +88 -0
  77. data/lib/pdk/validate/tasks_validator.rb +33 -0
  78. data/lib/pdk/version.rb +4 -0
  79. data/locales/config.yaml +21 -0
  80. data/locales/pdk.pot +1283 -0
  81. 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,13 @@
1
+ module PDK
2
+ module Util
3
+ module Windows
4
+ module File; end
5
+
6
+ if Gem.win_platform?
7
+ require 'pdk/util/windows/api_types'
8
+ require 'pdk/util/windows/string'
9
+ require 'pdk/util/windows/file'
10
+ end
11
+ end
12
+ end
13
+ 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
@@ -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