pdi 2.0.0.pre.alpha

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.
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'status'
11
+
12
+ module Pdi
13
+ class Executor
14
+ # General return object for an execution call result.
15
+ class Result
16
+ extend Forwardable
17
+ acts_as_hashable
18
+
19
+ attr_reader :args, :status
20
+
21
+ def_delegators :status, :code, :out, :pid
22
+
23
+ def initialize(args:, status: {})
24
+ @args = args
25
+ @status = Status.make(status)
26
+
27
+ freeze
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Pdi
11
+ class Executor
12
+ # General return object for describing the operating system return data.
13
+ class Status
14
+ acts_as_hashable
15
+
16
+ attr_reader :code, :out, :pid
17
+
18
+ def initialize(code:, out: '', pid:)
19
+ @code = code
20
+ @out = out
21
+ @pid = pid
22
+
23
+ freeze
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'spoon/kitchen_error'
11
+ require_relative 'spoon/options'
12
+ require_relative 'spoon/pan_error'
13
+ require_relative 'spoon/parser'
14
+ require_relative 'spoon/result'
15
+
16
+ module Pdi
17
+ # This class is the main wrapper for PDI's pan and kitchen scripts.
18
+ class Spoon
19
+ DEFAULT_KITCHEN = 'kitchen.sh'
20
+ DEFAULT_PAN = 'pan.sh'
21
+
22
+ TYPES_TO_ERRORS = {
23
+ Options::Type::JOB => KitchenError,
24
+ Options::Type::TRANSFORMATION => PanError
25
+ }.freeze
26
+
27
+ attr_reader :args, :dir, :kitchen, :pan
28
+
29
+ def initialize(
30
+ args: [],
31
+ dir:,
32
+ kitchen: DEFAULT_KITCHEN,
33
+ pan: DEFAULT_PAN,
34
+ timeout_in_seconds: nil
35
+ )
36
+ assert_required(:dir, dir)
37
+ assert_required(:kitchen, kitchen)
38
+ assert_required(:pan, pan)
39
+
40
+ @args = Array(args)
41
+ @dir = File.expand_path(dir.to_s)
42
+ @kitchen = kitchen.to_s
43
+ @pan = pan.to_s
44
+ @executor = Executor.new(timeout_in_seconds: timeout_in_seconds)
45
+ @parser = Parser.new
46
+
47
+ freeze
48
+ end
49
+
50
+ # Returns a Spoon::Result instance when PDI returns error code 0 or else raises
51
+ # a KitchenError since Kitchen was used to run the version command.
52
+ def version
53
+ final_args = [kitchen_path] + args + [Options::Arg.new(Options::Arg::Key::VERSION)]
54
+
55
+ result = executor.run(final_args)
56
+ version_line = parser.version(result.out)
57
+
58
+ raise(KitchenError, result) if result.code != 0
59
+
60
+ Result.new(result, version_line)
61
+ end
62
+
63
+ # Returns an Executor::Result instance when PDI returns error code 0 or else raises
64
+ # a PanError (transformation) or KitchenError (job).
65
+ def run(options)
66
+ options = Options.make(options)
67
+ all_args = run_args(options)
68
+
69
+ executor.run(all_args).tap do |result|
70
+ raise(error_constant(options), result) if result.code != 0
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ attr_reader :executor, :parser
77
+
78
+ def error_constant(options)
79
+ TYPES_TO_ERRORS.fetch(options.type)
80
+ end
81
+
82
+ def run_args(options)
83
+ [script_path(options.type)] + args + options.to_args
84
+ end
85
+
86
+ def script_path(options_type)
87
+ if options_type == Options::Type::JOB
88
+ kitchen_path
89
+ elsif options_type == Options::Type::TRANSFORMATION
90
+ pan_path
91
+ end
92
+ end
93
+
94
+ def kitchen_path
95
+ File.join(dir, kitchen)
96
+ end
97
+
98
+ def pan_path
99
+ File.join(dir, pan)
100
+ end
101
+
102
+ def assert_required(name, value)
103
+ raise ArgumentError, "#{name} is required" if value.to_s.empty?
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Pdi
11
+ class Spoon
12
+ # This class subclasses Ruby's StandardError and provides a mapping to custom Kitchen
13
+ # specific error codes to messages.
14
+ # You can find the list of errors in Pentaho's documentation site, for example:
15
+ # https://help.pentaho.com/Documentation/8.0/Products/Data_Integration/Command_Line_Tools
16
+ class KitchenError < StandardError
17
+ MESSAGES = {
18
+ '1' => 'Errors occurred during processing',
19
+ '2' => 'An unexpected error occurred during loading or running of the job',
20
+ '7' => "The job couldn't be loaded from XML or the Repository",
21
+ '8' => 'Error loading steps or plugins (error in loading one of the plugins mostly)',
22
+ '9' => 'Command line usage printing'
23
+ }.freeze
24
+
25
+ attr_reader :execution
26
+
27
+ def initialize(execution)
28
+ @execution = execution
29
+
30
+ message = MESSAGES[execution.code.to_s] || 'Unknown'
31
+
32
+ super(message)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'options/level'
11
+ require_relative 'options/param'
12
+
13
+ module Pdi
14
+ class Spoon
15
+ # This class serves as the input for executing a transformation or job through Pan or Kitchen.
16
+ class Options
17
+ acts_as_hashable
18
+
19
+ module Type
20
+ JOB = :job
21
+ TRANSFORMATION = :transformation
22
+ end
23
+
24
+ TYPES_TO_KEYS = {
25
+ Type::JOB => Arg::Key::JOB,
26
+ Type::TRANSFORMATION => Arg::Key::TRANS
27
+ }.freeze
28
+
29
+ attr_reader :level,
30
+ :name,
31
+ :params,
32
+ :repository,
33
+ :type
34
+
35
+ def initialize(
36
+ level: Level::BASIC,
37
+ name:,
38
+ params: {},
39
+ repository:,
40
+ type:
41
+ )
42
+ raise ArgumentError, 'name is required' if name.to_s.empty?
43
+ raise ArgumentError, 'repository is required' if repository.to_s.empty?
44
+ raise ArgumentError, 'type is required' if type.to_s.empty?
45
+
46
+ @level = constant(Level, level)
47
+ @name = name.to_s
48
+ @params = params || {}
49
+ @repository = repository.to_s
50
+ @type = constant(Type, type)
51
+
52
+ freeze
53
+ end
54
+
55
+ def to_args
56
+ base_args + param_args
57
+ end
58
+
59
+ private
60
+
61
+ def key
62
+ TYPES_TO_KEYS.fetch(type)
63
+ end
64
+
65
+ def base_args
66
+ [
67
+ Arg.new(Arg::Key::REP, repository),
68
+ Arg.new(key, name),
69
+ Arg.new(Arg::Key::LEVEL, level)
70
+ ]
71
+ end
72
+
73
+ def param_args
74
+ params.map { |key, value| Param.new(key, value) }
75
+ end
76
+
77
+ def constant(constant, value)
78
+ constant.const_get(value.to_s.upcase.to_sym)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Pdi
11
+ class Spoon
12
+ class Options
13
+ # This class can form Pentaho-specific command-line arguments.
14
+ class Arg
15
+ COLON = ':'
16
+ DOUBLE_QUOTE = '"'
17
+ EMPTY = ''
18
+ HYPHEN = '-'
19
+ SPACE = ' '
20
+
21
+ module Key
22
+ JOB = :job
23
+ LEVEL = :level
24
+ PARAM = :param
25
+ REP = :rep
26
+ TRANS = :trans
27
+ VERSION = :version
28
+ end
29
+
30
+ attr_reader :key, :value
31
+
32
+ def initialize(key, value = '')
33
+ raise ArgumentError, 'key is required' if key.to_s.empty?
34
+
35
+ @key = Key.const_get(key.to_s.upcase.to_sym)
36
+ @value = value.to_s
37
+
38
+ freeze
39
+ end
40
+
41
+ def to_s
42
+ separator = value.to_s.empty? ? EMPTY : COLON
43
+ wrapper = wrap?(key, value) ? DOUBLE_QUOTE : EMPTY
44
+ prefix = HYPHEN
45
+
46
+ "#{wrapper}#{prefix}#{key}#{separator}#{value}#{wrapper}"
47
+ end
48
+
49
+ def hash
50
+ [key, value].hash
51
+ end
52
+
53
+ def ==(other)
54
+ other.instance_of?(self.class) &&
55
+ key == other.key &&
56
+ value == other.value
57
+ end
58
+ alias eql? ==
59
+
60
+ private
61
+
62
+ def wrap?(key, value)
63
+ key.to_s.include?(SPACE) || value.to_s.include?(SPACE)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Pdi
11
+ class Spoon
12
+ class Options
13
+ module Level
14
+ BASIC = 'Basic'
15
+ DETAILED = 'Detailed'
16
+ DEBUG = 'Debug'
17
+ ERROR = 'Error'
18
+ NOTHING = 'Nothing'
19
+ ROW_LEVEL = 'Rowlevel'
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'arg'
11
+
12
+ module Pdi
13
+ class Spoon
14
+ class Options
15
+ # This class sub-classes Arg and knows how to form param key-value pair arguments.
16
+ class Param < Arg
17
+ EQUALS = '='
18
+
19
+ attr_reader :key, :value
20
+
21
+ def initialize(key, value = '')
22
+ super(Key::PARAM, "#{key}#{EQUALS}#{value}")
23
+
24
+ freeze
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Pdi
11
+ class Spoon
12
+ # This class subclasses Ruby's StandardError and provides a mapping to custom Pan
13
+ # specific error codes to messages.
14
+ # You can find the list of errors in Pentaho's documentation site, for example:
15
+ # https://help.pentaho.com/Documentation/8.0/Products/Data_Integration/Command_Line_Tools
16
+ class PanError < StandardError
17
+ MESSAGES = {
18
+ '1' => 'Errors occurred during processing',
19
+ '2' => 'An unexpected error occurred during loading / running of the transformation',
20
+ '3' => 'Unable to prepare and initialize this transformation',
21
+ '7' => "The transformation couldn't be loaded from XML or the Repository",
22
+ '8' => 'Error loading steps or plugins (error in loading one of the plugins mostly)',
23
+ '9' => 'Command line usage printing'
24
+ }.freeze
25
+
26
+ attr_reader :execution
27
+
28
+ def initialize(execution)
29
+ @execution = execution
30
+
31
+ message = MESSAGES[execution.code.to_s] || 'Unknown'
32
+
33
+ super(message)
34
+ end
35
+ end
36
+ end
37
+ end