teuton 2.7.3 → 2.9.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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/docs/changelog/changelog.1.md +119 -0
  4. data/docs/changelog/changelog.2.md +105 -0
  5. data/docs/diagram.md +10 -10
  6. data/docs/dsl/expect.md +76 -23
  7. data/docs/dsl/export.md +6 -3
  8. data/docs/dsl/result.md +24 -30
  9. data/docs/dsl/send.md +34 -23
  10. data/docs/learn/02-target.md +32 -27
  11. data/docs/learn/13-feedback.md +8 -9
  12. data/docs/learn/25-expect-result.md +39 -0
  13. data/docs/learn/26-expect_sequence.md +79 -0
  14. data/docs/learn/27-run_script.md +91 -0
  15. data/docs/learn/28-upload.md +55 -0
  16. data/docs/learn/README.md +4 -15
  17. data/docs/videos.md +14 -8
  18. data/lib/teuton/case/case.rb +3 -3
  19. data/lib/teuton/case/config.rb +0 -5
  20. data/lib/teuton/case/dsl/all.rb +5 -1
  21. data/lib/teuton/case/dsl/expect.rb +20 -33
  22. data/lib/teuton/case/dsl/expect_exitcode.rb +31 -0
  23. data/lib/teuton/case/dsl/expect_sequence.rb +173 -0
  24. data/lib/teuton/case/dsl/getset.rb +0 -1
  25. data/lib/teuton/case/dsl/host.rb +5 -0
  26. data/lib/teuton/case/dsl/macro.rb +7 -4
  27. data/lib/teuton/case/dsl/run_script.rb +35 -0
  28. data/lib/teuton/case/dsl/send.rb +3 -3
  29. data/lib/teuton/case/dsl/upload.rb +42 -0
  30. data/lib/teuton/case/dsl/weight.rb +12 -0
  31. data/lib/teuton/case/execute/execute_ssh.rb +11 -7
  32. data/lib/teuton/case/host.rb +68 -0
  33. data/lib/teuton/case/play.rb +2 -6
  34. data/lib/teuton/{utils → case}/result/ext_array.rb +0 -1
  35. data/lib/teuton/{utils → case}/result/ext_compare.rb +0 -1
  36. data/lib/teuton/{utils → case}/result/ext_filter.rb +0 -2
  37. data/lib/teuton/{utils → case}/result/result.rb +13 -21
  38. data/lib/teuton/check/checker.rb +82 -0
  39. data/lib/teuton/check/dsl/all.rb +37 -0
  40. data/lib/teuton/check/{builtin.rb → dsl/builtin.rb} +1 -3
  41. data/lib/teuton/check/dsl/expect.rb +90 -0
  42. data/lib/teuton/check/dsl/expect_sequence.rb +29 -0
  43. data/lib/teuton/check/dsl/getset.rb +23 -0
  44. data/lib/teuton/check/dsl/run.rb +35 -0
  45. data/lib/teuton/check/main.rb +29 -0
  46. data/lib/teuton/check/show.rb +75 -100
  47. data/lib/teuton/{utils → deprecated}/application.rb +0 -6
  48. data/lib/teuton/deprecated/application_test.rb +32 -0
  49. data/lib/teuton/readme/dsl/all.rb +32 -0
  50. data/lib/teuton/readme/dsl/expect.rb +29 -0
  51. data/lib/teuton/readme/dsl/getset.rb +33 -0
  52. data/lib/teuton/readme/dsl/run.rb +51 -0
  53. data/lib/teuton/readme/lang.rb +8 -10
  54. data/lib/teuton/readme/main.rb +27 -0
  55. data/lib/teuton/readme/readme.rb +31 -58
  56. data/lib/teuton/readme/result.rb +7 -0
  57. data/lib/teuton/report/formatter/default/txt.rb +2 -2
  58. data/lib/teuton/utils/configfile_reader.rb +8 -4
  59. data/lib/teuton/utils/logger.rb +32 -0
  60. data/lib/teuton/utils/verbose.rb +1 -1
  61. data/lib/teuton/version.rb +1 -1
  62. data/lib/teuton.rb +6 -5
  63. metadata +45 -37
  64. data/docs/CHANGELOG.md +0 -10
  65. data/docs/changelog/v2.0.md +0 -18
  66. data/docs/changelog/v2.1.md +0 -54
  67. data/docs/changelog/v2.2.md +0 -42
  68. data/docs/changelog/v2.3.md +0 -10
  69. data/docs/changelog/v2.4.md +0 -41
  70. data/docs/changelog/v2.5.md +0 -6
  71. data/docs/changelog/v2.6.md +0 -4
  72. data/docs/changelog/v2.7.md +0 -23
  73. data/docs/changelog/version2.1.md +0 -4
  74. data/docs/learn/videos.md +0 -13
  75. data/lib/teuton/case/execute/copy_ssh.rb +0 -70
  76. data/lib/teuton/check/dsl.rb +0 -112
  77. data/lib/teuton/check/laboratory.rb +0 -59
  78. data/lib/teuton/readme/dsl.rb +0 -126
  79. /data/lib/teuton/case/dsl/{goto.rb → run.rb} +0 -0
  80. /data/lib/teuton/{case/deprecated → deprecated}/runner.rb +0 -0
  81. /data/lib/teuton/{case/deprecated → deprecated}/utils.rb +0 -0
@@ -0,0 +1,173 @@
1
+ class ExpectSequence
2
+ attr_reader :result
3
+ attr_reader :states
4
+
5
+ def initialize(lines)
6
+ @lines = lines
7
+ end
8
+
9
+ def is_valid?(&block)
10
+ @expected = []
11
+ @states = [
12
+ {last_index: -1, steps: [], found: []}
13
+ ]
14
+ instance_eval(&block)
15
+ @result = find_best_state
16
+ @result[:ok]
17
+ end
18
+
19
+ def expected
20
+ @expected.join(">")
21
+ end
22
+
23
+ def real
24
+ # From final result return evaluation progress
25
+ text = []
26
+ @result[:steps].each do |step|
27
+ index = text.size
28
+ text << if step
29
+ @expected[index]
30
+ else
31
+ "not #{@expected[index]}"
32
+ end
33
+ end
34
+ text.join(">")
35
+ end
36
+
37
+ private
38
+
39
+ def find_best_state
40
+ @states.each do |state|
41
+ state[:score] = (state[:steps].select { _1 }).size
42
+ state[:fails] = (state[:steps].select { !_1 }).size
43
+ state[:ok] = (state[:fails] == 0)
44
+ end
45
+ best = @states[0]
46
+ @states.each { |state| best = state if state[:score] > best[:score] }
47
+ best
48
+ end
49
+
50
+ def find(value)
51
+ @expected << "find(#{value})"
52
+ newstates = []
53
+ @states.each do |state|
54
+ last_index = state[:last_index]
55
+
56
+ if last_index > (@lines.size - 1)
57
+ steps = state[:steps].clone
58
+ steps << false
59
+ newstates << {
60
+ last_index: last_index,
61
+ steps: steps,
62
+ found: state[:found].clone
63
+ }
64
+ next
65
+ end
66
+
67
+ findindexes = get_indexes(value: value, from: last_index)
68
+ findindexes.each do |findindex|
69
+ found = state[:found].clone
70
+ found << findindex
71
+ steps = state[:steps].clone
72
+ steps << true
73
+ newstates << {
74
+ last_index: findindex,
75
+ steps: steps,
76
+ found: found
77
+ }
78
+ end
79
+ end
80
+ @states = if newstates.size.zero?
81
+ @states.each { |state| state[:steps] << false }
82
+ else
83
+ newstates
84
+ end
85
+ end
86
+
87
+ def next_to(value)
88
+ @expected << "next_to(#{value})"
89
+ newstates = []
90
+
91
+ @states.each do |state|
92
+ last_index = state[:last_index]
93
+
94
+ if last_index > (@lines.size - 1)
95
+ steps = state[:steps].clone
96
+ steps << false
97
+ newstates << {
98
+ last_index: last_index,
99
+ steps: steps,
100
+ found: state[:found].clone
101
+ }
102
+ next
103
+ end
104
+
105
+ last_index += 1
106
+ found = state[:found].clone
107
+ steps = state[:steps].clone
108
+ line = @lines[last_index]
109
+ if line.include?(value)
110
+ found << last_index
111
+ steps << true
112
+ else
113
+ steps << false
114
+ end
115
+ newstates << {
116
+ last_index: last_index,
117
+ steps: steps,
118
+ found: found
119
+ }
120
+ end
121
+ @states = if newstates.size.zero?
122
+ @states.each { |state| state[:steps] << false }
123
+ else
124
+ newstates
125
+ end
126
+ end
127
+
128
+ def ignore(value)
129
+ @expected << "ignore(#{value})"
130
+ newstates = []
131
+ @states.each do |state|
132
+ last_index = state[:last_index] + value.to_i
133
+
134
+ steps = state[:steps].clone
135
+ steps << !(last_index > (@lines.size - 1))
136
+
137
+ newstates << {
138
+ last_index: last_index,
139
+ steps: steps,
140
+ found: state[:found].clone
141
+ }
142
+ end
143
+
144
+ @states = if newstates.size.zero?
145
+ @states.each { |state| state[:steps] << false }
146
+ else
147
+ newstates
148
+ end
149
+ end
150
+
151
+ def get_indexes(value:, from:)
152
+ indexes = []
153
+
154
+ @lines.each_with_index do |line, index|
155
+ next if index < from
156
+
157
+ indexes << index if line_include_value?(line: line, value: value)
158
+ end
159
+ indexes
160
+ end
161
+
162
+ def line_include_value?(line:, value:)
163
+ if value.is_a? String
164
+ return true if line.include? value
165
+ elsif value.is_a? Regexp
166
+ return true << index if value.match(line)
167
+ else
168
+ puts "[ERROR] expect_sequence #{value.class}"
169
+ exit 1
170
+ end
171
+ false
172
+ end
173
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # DSL#get and DSL#set
4
3
  module DSL
5
4
  # Read param option from [running, config or global] Hash data
6
5
  def get(option)
@@ -0,0 +1,5 @@
1
+ module DSL
2
+ def get_host(id)
3
+ Case::Host.new(config).get(id)
4
+ end
5
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../../utils/project"
4
+ require_relative "../../utils/logger"
4
5
 
5
- # DSL module methods: assert, missing_method
6
6
  module DSL
7
7
  ##
8
8
  # Invoke macro
@@ -11,7 +11,9 @@ module DSL
11
11
  def macro(name, input = {})
12
12
  macros = Project.value[:macros]
13
13
  unless macros[name]
14
- log("Macro #{name} not found!", :error)
14
+ msg = "DSL '#{name}' not found!"
15
+ log(msg, :error)
16
+ Logger.error("ERROR #{msg}")
15
17
  return
16
18
  end
17
19
  input.each_pair { |k, v| set(k, v) }
@@ -33,9 +35,10 @@ module DSL
33
35
  def method_missing(method, args = {})
34
36
  a = method.to_s
35
37
  if a.start_with?("_")
36
- return instance_eval("get(:#{a[1, a.size - 1]})", __FILE__, __LINE__)
38
+ return instance_eval("get(:#{a[1, a.size]})", __FILE__, __LINE__)
39
+ elsif a[0, 6] == "macro_"
40
+ return macro a[6, a.size], args
37
41
  end
38
- return macro a[6, a.size], args if a[0, 6] == "macro_"
39
42
  macro a, args
40
43
  end
41
44
 
@@ -0,0 +1,35 @@
1
+ require_relative "../../utils/project"
2
+ require_relative "../../utils/verbose"
3
+
4
+ module DSL
5
+ def run_script(script, args = {})
6
+ items = script.split(" ")
7
+ if items.size == 1
8
+ shell = args[:shell] || ((get(:shell) != "NODATA") ? get(:shell) : nil)
9
+ script = "#{shell} #{script}" if shell
10
+ script = "#{script} #{args[:args]} " if args[:args]
11
+ end
12
+
13
+ items = script.split(" ")
14
+ if items.size < 1
15
+ msg = Rainbow("==> [ERROR] run_script: Incorrect command '#{command}'").red
16
+ verboseln(msg)
17
+ return
18
+ end
19
+
20
+ host = get_host(args[:on])
21
+ if host.protocol == "local"
22
+ items[1] = File.join(Project.value[:project_path], items[1])
23
+ command = items.join(" ")
24
+ run(command, args)
25
+ elsif host.protocol == "ssh"
26
+ upload items[1], to: host.id
27
+ items[1] = File.basename(items[1])
28
+ command = items.join(" ")
29
+ run(command, args)
30
+ else
31
+ msg = Rainbow("==> [ERROR] run_script: Incorrect protocol(#{host.protocol})").red
32
+ verboseln(msg)
33
+ end
34
+ end
35
+ end
@@ -21,8 +21,8 @@ module DSL
21
21
  localfilepath = File.join(@report.output_dir, filename)
22
22
  filename = args[:prefix].to_s + filename if args[:prefix]
23
23
 
24
- remotefilepath = if args[:remote_dir]
25
- File.join(args[:remote_dir], filename)
24
+ remotefilepath = if args[:dir]
25
+ File.join(args[:dir], filename)
26
26
  else
27
27
  File.join(".", filename)
28
28
  end
@@ -32,7 +32,7 @@ module DSL
32
32
  Net::SFTP.start(ip, username, password: password, port: port) do |sftp|
33
33
  sftp.upload!(localfilepath, remotefilepath)
34
34
  end
35
- msg = Rainbow("==> File '#{remotefilepath}' of '#{get(:tt_members)}' has been copied").green
35
+ msg = Rainbow("==> Case #{get(:tt_members)}: report (#{remotefilepath}) copy to (#{ip})").green
36
36
  verboseln(msg)
37
37
  rescue
38
38
  msg = Rainbow("==> [FAIL] #{get(:tt_members)}: 'scp #{localfilepath}' to #{remotefilepath}").red
@@ -0,0 +1,42 @@
1
+ require_relative "../../utils/project"
2
+ require_relative "../../utils/verbose"
3
+
4
+ module DSL
5
+ def upload(localfilter, args = {})
6
+ abslocalfilter = if File.absolute_path? localfilter
7
+ localfilter
8
+ else
9
+ File.join(Project.value[:project_path], localfilter)
10
+ end
11
+
12
+ Dir.glob(abslocalfilter).each do |abslocalpath|
13
+ upload_one(abslocalpath, args)
14
+ end
15
+ end
16
+
17
+ def upload_one(localpath, args = {})
18
+ if args[:to].nil?
19
+ Logger.err("ERROR upload requires to: XXX")
20
+ exit 1
21
+ end
22
+
23
+ host = get_host(args[:to])
24
+ if host.protocol == "ssh"
25
+ begin
26
+ localfile = File.basename(localpath)
27
+ remotepath = args[:remotedir] ? File.join(args[:remotedir], localfile) : localfile
28
+ Net::SFTP.start(
29
+ host.ip, host.username, password: host.password, port: host.port
30
+ ) { |sftp| sftp.upload!(localpath, remotepath) }
31
+ verbose(Rainbow("u").green)
32
+ rescue => e
33
+ log("Upload #{localfile} to #{host.ip}:#{remotepath}", :warn)
34
+ log(e.to_s, :warn)
35
+ verbose(Rainbow("!").green)
36
+ end
37
+ elsif host.protocol != "local"
38
+ msg = Rainbow("==> [ERROR] upload: Incorrect protocol(#{host.protocol})").red
39
+ verboseln(msg)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ module DSL
2
+ def weight(value = nil)
3
+ # Set weight value for the action
4
+ if value.nil?
5
+ @action[:weight]
6
+ elsif value == :default
7
+ @action[:weight] = 1.0
8
+ else
9
+ @action[:weight] = value.to_f
10
+ end
11
+ end
12
+ end
@@ -35,7 +35,7 @@ class ExecuteSSH < ExecuteBase
35
35
  end
36
36
  end
37
37
 
38
- text = ""
38
+ text = "TEUTON_NODATA"
39
39
  exitcode = 0
40
40
  begin
41
41
  if sessions[hostname].nil?
@@ -49,25 +49,29 @@ class ExecuteSSH < ExecuteBase
49
49
  non_interactive: true
50
50
  )
51
51
  end
52
- text = if sessions[hostname].instance_of? Net::SSH::Connection::Session
53
- sessions[hostname].exec!(action[:command])
52
+ if sessions[hostname].instance_of? Net::SSH::Connection::Session
53
+ text = sessions[hostname].exec!(action[:command])
54
+ exitcode = text.exitstatus
54
55
  else
55
- "SSH: NO CONNECTION!"
56
+ text = "TEUTON_ERROR_SSH_NO_CONNECTION"
57
+ exitcode = -1
56
58
  end
57
- exitcode = text.exitstatus
58
59
  rescue Errno::EHOSTUNREACH
59
60
  sessions[hostname] = :nosession
60
61
  conn_status[hostname] = :host_unreachable
62
+ text = "TEUTON_ERROR_SSH_HOST_UNREACHABLE"
61
63
  exitcode = -1
62
64
  log("Host #{ip} unreachable!", :error)
63
65
  rescue Net::SSH::AuthenticationFailed
64
66
  sessions[hostname] = :nosession
65
67
  conn_status[hostname] = :error_authentication_failed
68
+ text = "TEUTON_ERROR_SSH_AUTH_FAILED"
66
69
  exitcode = -1
67
70
  log("SSH::AuthenticationFailed!", :error)
68
71
  rescue Net::SSH::HostKeyMismatch
69
72
  sessions[hostname] = :nosession
70
73
  conn_status[hostname] = :host_key_mismatch
74
+ text = "TEUTON_ERROR_SSH_HOST_KEY"
71
75
  exitcode = -1
72
76
  log("SSH::HostKeyMismatch!", :error)
73
77
  log("* The destination server's fingerprint is not matching " \
@@ -78,13 +82,13 @@ class ExecuteSSH < ExecuteBase
78
82
  rescue => e
79
83
  sessions[hostname] = :nosession
80
84
  conn_status[hostname] = :error
85
+ text = "TEUTON_ERROR_SSH"
81
86
  exitcode = -1
82
87
  log("[#{e.class}] SSH on <#{username}@#{ip}>" \
83
88
  " exec: #{action[:command]}", :error)
84
89
  end
85
- output = encode_and_split(action[:encoding], text)
86
90
  result.exitcode = exitcode
87
- result.content = output
91
+ result.content = encode_and_split(action[:encoding], text)
88
92
  result.content.compact!
89
93
  end
90
94
  end
@@ -0,0 +1,68 @@
1
+ class Case
2
+ class Host
3
+ attr_reader :id
4
+ attr_reader :ip
5
+ attr_reader :username
6
+ attr_reader :password
7
+ attr_reader :port
8
+ attr_reader :protocol
9
+ attr_reader :route
10
+
11
+ def initialize(config)
12
+ @config = config
13
+ end
14
+
15
+ def get(id = nil)
16
+ if id.nil?
17
+ init_default
18
+ else
19
+ init(id)
20
+ end
21
+ self
22
+ end
23
+
24
+ def to_s
25
+ data = {
26
+ id: id,
27
+ ip: ip, username: username, password: password,
28
+ port: port, protocol: protocol, route: route
29
+ }
30
+ data.to_s
31
+ end
32
+
33
+ private
34
+
35
+ def init(id)
36
+ @id = id.to_sym
37
+ @ip = @config.get("#{@id}_ip".to_sym).to_s
38
+ @username = @config.get("#{@id}_username".to_sym).to_s
39
+ @password = @config.get("#{@id}_password".to_sym).to_s
40
+
41
+ @protocol = @config.get("#{@id}_protocol".to_sym).to_s.downcase
42
+ if @protocol == "nodata"
43
+ @protocol = if @ip == "localhost" || @ip.start_with?("127.0.0.")
44
+ "local"
45
+ else
46
+ "ssh"
47
+ end
48
+ end
49
+
50
+ @port = @config.get("#{@id}_port".to_sym).to_i
51
+ if @port.zero?
52
+ default = {"local" => 0, "ssh" => 22, "telnet" => 23}
53
+ @port = default[@protocol]
54
+ end
55
+ @route = @config.get("#{@id}_route".to_sym)
56
+ end
57
+
58
+ def init_default
59
+ @id = :default
60
+ @ip = "localhost"
61
+ @username = "NODATA"
62
+ @password = "NODATA"
63
+ @protocol = "local"
64
+ @port = 0
65
+ @route = "NODATA"
66
+ end
67
+ end
68
+ end
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Case
4
- # Case class: play
5
- # TODO: Encapsulate code into PlayManager class
6
- # * play_in_parallel, play_in_sequence, fill_report, close_opened_sessions
7
4
  # READ: sessions, config, groups, action, report
8
5
  # TODO: groups from Project or from Case???
9
6
  def play
@@ -18,19 +15,18 @@ class Case
18
15
  end
19
16
  alias_method :start, :play
20
17
 
18
+ private
19
+
21
20
  def close_opened_sessions
22
21
  @sessions.each_value do |s|
23
22
  s.close if s.instance_of? Net::SSH::Connection::Session
24
23
  end
25
24
  end
26
25
 
27
- private
28
-
29
26
  def play_groups_in_sequence
30
27
  verboseln "\n=> Starting case [#{@config.get(:tt_members)}]" if get(:tt_sequence) == true
31
28
  @groups.each do |t|
32
29
  @action[:groupname] = t[:name]
33
- # TODO: @parent(case).instance_eval(&t[:block])
34
30
  instance_eval(&t[:block])
35
31
  end
36
32
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # This is an extension of Result class
4
3
  class Result
5
4
  def count
6
5
  @alterations << "count"
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Extension of Result class
4
3
  class Result
5
4
  def eq(input)
6
5
  # Return true when content is equal than input
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Result class extension
4
3
  class Result
5
- # TODO: Error line 102 undefined include? method for 0 Fixnum...
6
4
  def find(filter)
7
5
  @alterations << "find(#{filter})"
8
6
  case filter.class.to_s
@@ -4,15 +4,6 @@ require_relative "ext_array"
4
4
  require_relative "ext_compare"
5
5
  require_relative "ext_filter"
6
6
 
7
- # This object contains data returned by remote/local execution
8
- # * initialize
9
- # * alterations
10
- # * content
11
- # * debug
12
- # * ok?
13
- # * reset
14
- # * restore
15
- # * value
16
7
  class Result
17
8
  attr_reader :content
18
9
  attr_accessor :exitcode
@@ -22,6 +13,16 @@ class Result
22
13
  reset
23
14
  end
24
15
 
16
+ def reset
17
+ @content_backup = []
18
+ @content = []
19
+ @exitcode = -1
20
+
21
+ # @value = nil
22
+ @expected = nil
23
+ @alterations = []
24
+ end
25
+
25
26
  def alterations
26
27
  if @alterations.is_a? String
27
28
  @alterations
@@ -49,15 +50,6 @@ class Result
49
50
  @expected.to_s
50
51
  end
51
52
 
52
- def reset
53
- @content_backup = []
54
- @content = []
55
- @exitcode = -1
56
- @value = nil
57
- @expected = nil
58
- @alterations = []
59
- end
60
-
61
53
  def ok?
62
54
  @exitcode.zero?
63
55
  end
@@ -65,10 +57,10 @@ class Result
65
57
  def restore
66
58
  temp = @content_backup.clone
67
59
  reset
68
- @content_backup = temp
69
- @content = temp.clone
60
+ # @content_backup = temp
61
+ # @content = temp.clone
62
+ self.content = (temp)
70
63
  end
71
- alias_method :restore!, :restore
72
64
 
73
65
  def value
74
66
  @content[0]
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../case/dsl/macro"
4
+ require_relative "../case/result/result"
5
+ require_relative "../utils/project"
6
+ require_relative "../utils/logger"
7
+ require_relative "dsl/all"
8
+ require_relative "show"
9
+
10
+ class Checker
11
+ include DSL # Include case/DSL/macro functions only
12
+ include CheckDSL
13
+
14
+ attr_reader :result
15
+
16
+ def initialize(script_path, config_path)
17
+ @path = {}
18
+ @path[:script] = script_path
19
+ @path[:dirname] = File.dirname(script_path)
20
+ @path[:filename] = File.basename(script_path, ".rb")
21
+ @path[:config] = config_path
22
+ reset
23
+ end
24
+
25
+ def reset
26
+ @result = Result.new
27
+ @targetid = 0
28
+ @stats = {
29
+ groups: 0,
30
+ targets: 0,
31
+ logs: 0,
32
+ readmes: 0,
33
+ uniques: 0,
34
+ hosts: {},
35
+ gets: {},
36
+ sets: [],
37
+ uploads: []
38
+ }
39
+ @target_begin = nil
40
+ end
41
+
42
+ def show
43
+ Logger.verbose = true
44
+ process_content
45
+ cs = ShowCheck.new(stats: @stats, path: @path)
46
+ cs.show_stats
47
+ cs.revise_config_content
48
+ end
49
+
50
+ def show_onlyconfig
51
+ Logger.verbose = false
52
+ process_content
53
+ Logger.verbose = true
54
+ cs = ShowCheck.new(stats: @stats, path: @path)
55
+ cs.suggest_config_content
56
+ end
57
+
58
+ private
59
+
60
+ def process_content
61
+ groups = Project.value[:groups]
62
+ option = Project.value[:options]
63
+
64
+ Logger.info ""
65
+ if Project.value[:uses].size.positive?
66
+ Logger.info Terminal::Table.new { |st| st.add_row ["USE: external libraries"] }
67
+ Project.value[:uses].each_with_index { Logger.info " #{_2 + 1}. #{_1}" }
68
+ end
69
+ groups.each do |t|
70
+ @stats[:groups] += 1
71
+ unless option[:panel]
72
+ msg = "GROUP: #{t[:name]}"
73
+ my_screen_table = Terminal::Table.new { |st| st.add_row [msg] }
74
+ Logger.info my_screen_table
75
+ end
76
+ instance_eval(&t[:block])
77
+ end
78
+ if @target_begin
79
+ Logger.warn "WARN Last 'target' requires 'expect'\n"
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,37 @@
1
+ require_relative "builtin"
2
+ require_relative "expect"
3
+ require_relative "getset"
4
+ require_relative "run"
5
+
6
+ module CheckDSL
7
+ def log(text = "", type = :info)
8
+ @stats[:logs] += 1
9
+ prefix = (type == :info) ? "" : "#{type.to_s.upcase}: "
10
+ Logger.info " log #{prefix}" + text.to_s
11
+ end
12
+
13
+ def readme(text)
14
+ @stats[:readmes] += 1
15
+ Logger.info " readme #{text}"
16
+ end
17
+
18
+ def target(desc, args = {})
19
+ if @target_begin
20
+ Logger.warn "WARN Previous 'target' requires 'expect'"
21
+ end
22
+ @target_begin = true
23
+ @stats[:targets] += 1
24
+ @targetid += 1
25
+ weight = args[:weight] ? args[:weight].to_f : 1.0
26
+ Logger.info format("(%03<targetid>d) target %<desc>s", targetid: @targetid, desc: desc)
27
+ Logger.info " weight #{weight}"
28
+ end
29
+ alias_method :goal, :target
30
+
31
+ def unique(key, _value)
32
+ @stats[:uniques] += 1
33
+
34
+ Logger.info " unique value for <#{key}>"
35
+ Logger.info ""
36
+ end
37
+ end