teuton 0.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/bin/teuton +4 -0
- data/lib/teuton/application.rb +53 -0
- data/lib/teuton/case_manager/case/builtin/main.rb +24 -0
- data/lib/teuton/case_manager/case/builtin/package.rb +20 -0
- data/lib/teuton/case_manager/case/builtin/service.rb +32 -0
- data/lib/teuton/case_manager/case/builtin/user.rb +20 -0
- data/lib/teuton/case_manager/case/case.rb +114 -0
- data/lib/teuton/case_manager/case/close.rb +29 -0
- data/lib/teuton/case_manager/case/config.rb +76 -0
- data/lib/teuton/case_manager/case/dsl/check.rb +24 -0
- data/lib/teuton/case_manager/case/dsl/deprecated.rb +14 -0
- data/lib/teuton/case_manager/case/dsl/expect.rb +78 -0
- data/lib/teuton/case_manager/case/dsl/getset.rb +22 -0
- data/lib/teuton/case_manager/case/dsl/goto.rb +35 -0
- data/lib/teuton/case_manager/case/dsl/log.rb +14 -0
- data/lib/teuton/case_manager/case/dsl/main.rb +11 -0
- data/lib/teuton/case_manager/case/dsl/missing.rb +12 -0
- data/lib/teuton/case_manager/case/dsl/send.rb +69 -0
- data/lib/teuton/case_manager/case/dsl/target.rb +16 -0
- data/lib/teuton/case_manager/case/dsl/unique.rb +11 -0
- data/lib/teuton/case_manager/case/main.rb +7 -0
- data/lib/teuton/case_manager/case/play.rb +59 -0
- data/lib/teuton/case_manager/case/result/ext_array.rb +43 -0
- data/lib/teuton/case_manager/case/result/ext_compare.rb +147 -0
- data/lib/teuton/case_manager/case/result/ext_filter.rb +68 -0
- data/lib/teuton/case_manager/case/result/result.rb +73 -0
- data/lib/teuton/case_manager/case/runner.rb +134 -0
- data/lib/teuton/case_manager/case_manager.rb +76 -0
- data/lib/teuton/case_manager/check_cases.rb +73 -0
- data/lib/teuton/case_manager/dsl.rb +31 -0
- data/lib/teuton/case_manager/export_manager.rb +20 -0
- data/lib/teuton/case_manager/hall_of_fame.rb +28 -0
- data/lib/teuton/case_manager/main.rb +6 -0
- data/lib/teuton/case_manager/report.rb +52 -0
- data/lib/teuton/case_manager/show.rb +19 -0
- data/lib/teuton/case_manager/utils.rb +57 -0
- data/lib/teuton/command/create.rb +20 -0
- data/lib/teuton/command/download.rb +26 -0
- data/lib/teuton/command/main.rb +9 -0
- data/lib/teuton/command/play.rb +34 -0
- data/lib/teuton/command/readme.rb +23 -0
- data/lib/teuton/command/test.rb +35 -0
- data/lib/teuton/command/update.rb +27 -0
- data/lib/teuton/command/version.rb +13 -0
- data/lib/teuton/files/start.rb +13 -0
- data/lib/teuton/project/configfile_reader.rb +49 -0
- data/lib/teuton/project/laboratory/builtin.rb +23 -0
- data/lib/teuton/project/laboratory/dsl.rb +117 -0
- data/lib/teuton/project/laboratory/laboratory.rb +55 -0
- data/lib/teuton/project/laboratory/show.rb +161 -0
- data/lib/teuton/project/name_file_finder.rb +129 -0
- data/lib/teuton/project/project.rb +62 -0
- data/lib/teuton/project/project_creator.rb +79 -0
- data/lib/teuton/project/readme/dsl.rb +109 -0
- data/lib/teuton/project/readme/lang.rb +30 -0
- data/lib/teuton/project/readme/readme.rb +156 -0
- data/lib/teuton/rake_function/check.rb +39 -0
- data/lib/teuton/rake_function/install.rb +36 -0
- data/lib/teuton/report/close.rb +34 -0
- data/lib/teuton/report/formatter/array_formatter.rb +84 -0
- data/lib/teuton/report/formatter/base_formatter.rb +33 -0
- data/lib/teuton/report/formatter/csv_formatter.rb +31 -0
- data/lib/teuton/report/formatter/formatter_factory.rb +73 -0
- data/lib/teuton/report/formatter/html_formatter.rb +81 -0
- data/lib/teuton/report/formatter/json_formatter.rb +17 -0
- data/lib/teuton/report/formatter/list_formatter.rb +71 -0
- data/lib/teuton/report/formatter/moodle_csv_formatter.rb +28 -0
- data/lib/teuton/report/formatter/resume_array_formatter.rb +49 -0
- data/lib/teuton/report/formatter/resume_json_formatter.rb +16 -0
- data/lib/teuton/report/formatter/resume_list_formatter.rb +62 -0
- data/lib/teuton/report/formatter/resume_txt_formatter.rb +102 -0
- data/lib/teuton/report/formatter/resume_yaml_formatter.rb +16 -0
- data/lib/teuton/report/formatter/txt_formatter.rb +102 -0
- data/lib/teuton/report/formatter/xml_formatter.rb +42 -0
- data/lib/teuton/report/formatter/yaml_formatter.rb +18 -0
- data/lib/teuton/report/report.rb +55 -0
- data/lib/teuton/report/show.rb +111 -0
- data/lib/teuton/utils/verbose.rb +15 -0
- data/lib/teuton.rb +17 -0
- metadata +263 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require_relative '../application'
|
|
2
|
+
require_relative 'case_manager'
|
|
3
|
+
|
|
4
|
+
def use(filename)
|
|
5
|
+
filename += '.rb'
|
|
6
|
+
app = Application.instance
|
|
7
|
+
rbfiles = File.join(app.project_path, "**", filename)
|
|
8
|
+
files = Dir.glob(rbfiles)
|
|
9
|
+
findfiles = []
|
|
10
|
+
files.sort.each { |f| findfiles << f if f.include?(filename) }
|
|
11
|
+
require_relative findfiles.first
|
|
12
|
+
app.uses << File.basename(findfiles.first)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def define_check(name, *args, &block)
|
|
16
|
+
Application.instance.checks[name] = { args: args, block: block }
|
|
17
|
+
end
|
|
18
|
+
alias definecheck define_check
|
|
19
|
+
alias def_check define_check
|
|
20
|
+
alias defcheck define_check
|
|
21
|
+
alias dcheck define_check
|
|
22
|
+
|
|
23
|
+
def group(name, &block)
|
|
24
|
+
Application.instance.groups << { name: name, block: block }
|
|
25
|
+
end
|
|
26
|
+
alias task group
|
|
27
|
+
|
|
28
|
+
def play(&block)
|
|
29
|
+
CaseManager.instance.play(&block)
|
|
30
|
+
end
|
|
31
|
+
alias start play
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../application'
|
|
4
|
+
|
|
5
|
+
# ExportManager#run
|
|
6
|
+
module ExportManager
|
|
7
|
+
def self.run(main_report, cases, args)
|
|
8
|
+
# default :mode=>:all, :format=>:txt
|
|
9
|
+
format = args[:format] || Application.instance.default[:format]
|
|
10
|
+
mode = args[:mode] || :all
|
|
11
|
+
# Export case reports
|
|
12
|
+
if %i[details all].include? mode
|
|
13
|
+
threads = []
|
|
14
|
+
cases.each { |c| threads << Thread.new { c.export format } }
|
|
15
|
+
threads.each(&:join)
|
|
16
|
+
end
|
|
17
|
+
# Export resume report
|
|
18
|
+
main_report.export_resume format if %i[resume all].include? mode
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
require_relative '../application'
|
|
3
|
+
|
|
4
|
+
class CaseManager
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def build_hall_of_fame
|
|
9
|
+
celebrities = {}
|
|
10
|
+
|
|
11
|
+
@cases.each do |c|
|
|
12
|
+
grade = c.grade # report.tail[:grade]
|
|
13
|
+
if celebrities[grade]
|
|
14
|
+
label = celebrities[grade] + '*'
|
|
15
|
+
else
|
|
16
|
+
label = '*'
|
|
17
|
+
end
|
|
18
|
+
celebrities[grade] = label unless c.skip
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
a = celebrities.sort_by { |key, _value| key }
|
|
22
|
+
list = a.reverse
|
|
23
|
+
|
|
24
|
+
app = Application.instance
|
|
25
|
+
app.options[:case_number] = @cases.size
|
|
26
|
+
app.hall_of_fame = list
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
|
|
2
|
+
class CaseManager
|
|
3
|
+
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def open_main_report(p_config_filename)
|
|
7
|
+
app = Application.instance
|
|
8
|
+
|
|
9
|
+
@report.head[:tt_title] = "Executing [#{app.name}] (version #{Application::VERSION})"
|
|
10
|
+
@report.head[:tt_scriptname] = app.script_path
|
|
11
|
+
@report.head[:tt_configfile] = p_config_filename
|
|
12
|
+
@report.head[:tt_debug] = true if @debug
|
|
13
|
+
# @report.head[:tt_uses] = app.uses.join(', ')
|
|
14
|
+
@report.head.merge!(app.global)
|
|
15
|
+
|
|
16
|
+
verboseln ' '
|
|
17
|
+
verboseln '=' * @report.head[:tt_title].length
|
|
18
|
+
verboseln @report.head[:tt_title]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def close_main_report(start_time)
|
|
22
|
+
finish_time = Time.now
|
|
23
|
+
@report.tail[:start_time] = start_time
|
|
24
|
+
@report.tail[:finish_time] = finish_time
|
|
25
|
+
@report.tail[:duration] = finish_time - start_time
|
|
26
|
+
|
|
27
|
+
verbose "\n[INFO] Duration = #{format('%3.3f',(finish_time - start_time))}"
|
|
28
|
+
verboseln " (#{finish_time})"
|
|
29
|
+
verboseln '=' * @report.head[:tt_title].length
|
|
30
|
+
verboseln ' '
|
|
31
|
+
|
|
32
|
+
app = Application.instance
|
|
33
|
+
@cases.each do |c|
|
|
34
|
+
line = {}
|
|
35
|
+
if c.skip?
|
|
36
|
+
line = { skip: true, id: '-', grade: 0.0, letter: '',
|
|
37
|
+
members: '-', conn_status: {},
|
|
38
|
+
moodle_id: '', moodle_feedback: '' }
|
|
39
|
+
else
|
|
40
|
+
line[:skip] = false
|
|
41
|
+
line[:id] = format('case_%02d', c.id.to_i)
|
|
42
|
+
line[:letter] = app.letter[:error] if c.grade < 50.0
|
|
43
|
+
line[:grade] = c.grade.to_f #format(' %3d', c.grade.to_f)
|
|
44
|
+
line[:members] = c.members
|
|
45
|
+
line[:conn_status] = c.conn_status
|
|
46
|
+
line[:moodle_id] = c.get(:tt_moodle_id)
|
|
47
|
+
line[:moodle_feedback] = "\"Filename: #{c.filename}. Date: #{Time.now}\""
|
|
48
|
+
end
|
|
49
|
+
@report.lines << line
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require_relative '../application'
|
|
3
|
+
|
|
4
|
+
# CaseManager#show
|
|
5
|
+
class CaseManager
|
|
6
|
+
def show(mode = :resume)
|
|
7
|
+
return if Application.instance.quiet?
|
|
8
|
+
|
|
9
|
+
@report.show if %i[resume all].include? mode
|
|
10
|
+
|
|
11
|
+
return unless %i[details all].include? mode
|
|
12
|
+
|
|
13
|
+
@cases.each do |c|
|
|
14
|
+
puts '____'
|
|
15
|
+
c.show
|
|
16
|
+
end
|
|
17
|
+
puts '.'
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../application'
|
|
4
|
+
|
|
5
|
+
# Define general use methods
|
|
6
|
+
module Utils
|
|
7
|
+
# Create the directory if it dosn't exist.
|
|
8
|
+
def ensure_dir(dirname)
|
|
9
|
+
unless Dir.exist?(dirname)
|
|
10
|
+
FileUtils.mkdir_p(dirname)
|
|
11
|
+
return false
|
|
12
|
+
end
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def encode_and_split(encoding, text)
|
|
17
|
+
# Convert text to UTF-8 deleting unknown chars
|
|
18
|
+
text = text || '' # Ensure text is not nil
|
|
19
|
+
flag = [:default, 'UTF-8'].include? encoding
|
|
20
|
+
return text.encode('UTF-8', invalid: :replace).split("\n") if flag
|
|
21
|
+
|
|
22
|
+
# Convert text from input ENCODING to UTF-8
|
|
23
|
+
ec = Encoding::Converter.new(encoding.to_s, 'UTF-8')
|
|
24
|
+
begin
|
|
25
|
+
text = ec.convert(text)
|
|
26
|
+
rescue StandardError => e
|
|
27
|
+
puts "[ERROR] #{e}: Declare text encoding..."
|
|
28
|
+
puts " goto :host, :exec => 'command', :encoding => 'ISO-8859-1'"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
text.split("\n")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def my_execute(cmd, encoding = 'UTF-8')
|
|
35
|
+
return { exitstatus: 0, content: '' } if Application.instance.debug
|
|
36
|
+
|
|
37
|
+
begin
|
|
38
|
+
text = `#{cmd}`
|
|
39
|
+
exitstatus = $CHILD_STATUS.exitstatus
|
|
40
|
+
rescue StandardError => e # rescue Exception => e
|
|
41
|
+
verbose '!'
|
|
42
|
+
puts("[ERROR] #{e}: Local exec: #{cmd}")
|
|
43
|
+
end
|
|
44
|
+
content = encode_and_split(encoding, text)
|
|
45
|
+
{ exitstatus: exitstatus, content: content }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def verboseln(text)
|
|
49
|
+
verbose(text + "\n")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def verbose(text)
|
|
53
|
+
return if Application.instance.quiet?
|
|
54
|
+
|
|
55
|
+
print text
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../project/project_creator.rb'
|
|
4
|
+
|
|
5
|
+
# Teuton#create
|
|
6
|
+
class Teuton < Thor
|
|
7
|
+
map ['c', '-c', '--create'] => 'create'
|
|
8
|
+
desc 'create DIRECTORY', 'Create skeleton for a new project'
|
|
9
|
+
long_desc <<-LONGDESC
|
|
10
|
+
Create files for a new project: foo.rb, foo.yaml and .gitignore
|
|
11
|
+
|
|
12
|
+
Example:
|
|
13
|
+
|
|
14
|
+
#{$PROGRAM_NAME} create foo/demo
|
|
15
|
+
|
|
16
|
+
LONGDESC
|
|
17
|
+
def create(path_to_new_dir)
|
|
18
|
+
ProjectCreator.create(path_to_new_dir)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rainbow'
|
|
4
|
+
|
|
5
|
+
# Class method Teuton#download
|
|
6
|
+
class Teuton < Thor
|
|
7
|
+
map ['-dc', '--dc', '--download'] => 'download'
|
|
8
|
+
desc 'download', 'Download Teuton challenges from git repo'
|
|
9
|
+
long_desc <<-LONGDESC
|
|
10
|
+
- Download Teuton challenges from git repo.
|
|
11
|
+
|
|
12
|
+
- Same as:
|
|
13
|
+
git clone https://github.com/teuton-software/teuton-challenges.git
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
|
|
17
|
+
#{$PROGRAM_NAME} download
|
|
18
|
+
|
|
19
|
+
LONGDESC
|
|
20
|
+
def download
|
|
21
|
+
repo = 'teuton-challenges'
|
|
22
|
+
puts "[INFO] Downloading <#{repo}> repo..."
|
|
23
|
+
system("git clone https://github.com/teuton-software/#{repo}.git")
|
|
24
|
+
puts "[INFO] Your files are into <#{Rainbow(repo).bright}> directory..."
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Teuton#play
|
|
4
|
+
class Teuton < Thor
|
|
5
|
+
map ['p', '-p', 'play', '--play'] => 'play'
|
|
6
|
+
option :export, type: :string
|
|
7
|
+
option :cname, type: :string
|
|
8
|
+
option :cpath, type: :string
|
|
9
|
+
option :case, type: :string
|
|
10
|
+
option :quiet, type: :boolean
|
|
11
|
+
desc '[play] [OPTIONS] DIRECTORY',
|
|
12
|
+
'Run challenge from directory'
|
|
13
|
+
long_desc <<-LONGDESC
|
|
14
|
+
This function execute challenge from specified directory.
|
|
15
|
+
By default, show progress on the screen.
|
|
16
|
+
|
|
17
|
+
Let's see others options:
|
|
18
|
+
|
|
19
|
+
(1) teuton foo, run challenge from foo/start.rb with foo/config.yaml config file.
|
|
20
|
+
|
|
21
|
+
(2) teuton play foo, same as (1).
|
|
22
|
+
|
|
23
|
+
(3) teuton play --export=json foo, run challenge and export using json format.
|
|
24
|
+
Others output formats availables are: txt, colored_text, json, yaml.
|
|
25
|
+
|
|
26
|
+
(4) teuton play --cname=demo foo, run challenge from foo/start.rb with foo/demo.yaml config file.
|
|
27
|
+
|
|
28
|
+
(5) teuton foo/demo.rb, Run challenge from foo/demo.rb with foo/demo.yaml config file.
|
|
29
|
+
|
|
30
|
+
LONGDESC
|
|
31
|
+
def play(path_to_rb_file)
|
|
32
|
+
Project.play(path_to_rb_file, options)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Teuton#readme
|
|
4
|
+
class Teuton < Thor
|
|
5
|
+
map ['r', '-r', '--readme'] => 'readme'
|
|
6
|
+
option :lang, type: :string
|
|
7
|
+
desc 'readme DIRECTORY',
|
|
8
|
+
'Create README.md file from challenge contents'
|
|
9
|
+
long_desc <<-LONGDESC
|
|
10
|
+
|
|
11
|
+
(1) teuton readme foo
|
|
12
|
+
, Create README.md from foo/start.rb.
|
|
13
|
+
|
|
14
|
+
(2) teuton readme foo/demo.rb
|
|
15
|
+
, Create README.md from foo/demo.rb.
|
|
16
|
+
|
|
17
|
+
By default lang=es, but It's available lang=en too.
|
|
18
|
+
|
|
19
|
+
LONGDESC
|
|
20
|
+
def readme(path_to_rb_file)
|
|
21
|
+
Project.readme(path_to_rb_file, options)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Teuton#test
|
|
4
|
+
class Teuton < Thor
|
|
5
|
+
map ['t', '-t', '--test'] => 'test'
|
|
6
|
+
option :c, type: :boolean
|
|
7
|
+
option :cname, type: :string
|
|
8
|
+
option :cpath, type: :string
|
|
9
|
+
desc 'test [OPTIONS] DIRECTORY',
|
|
10
|
+
'Test or check challenge contents'
|
|
11
|
+
long_desc <<-LONGDESC
|
|
12
|
+
|
|
13
|
+
(1) teuton test path/to/dir/foo
|
|
14
|
+
, Test content of start.rb and config.yaml files.
|
|
15
|
+
|
|
16
|
+
(2) teuton test path/to/dir/foo -c
|
|
17
|
+
, Only test CONFIG information from config.yaml.
|
|
18
|
+
|
|
19
|
+
(3) teuton test path/to/dir/foo --cname=demo
|
|
20
|
+
, Test content of start.rb and demo.yaml files.
|
|
21
|
+
|
|
22
|
+
(4) teuton test path/to/file/foo.rb
|
|
23
|
+
, Test content of foo.rb and foo.yaml files.
|
|
24
|
+
|
|
25
|
+
(5) teuton test path/to/file/foo.rb -c
|
|
26
|
+
, Only test CONFIG information from foo.yaml.
|
|
27
|
+
|
|
28
|
+
(6) teuton test path/to/file/foo.rb --cname=demo
|
|
29
|
+
, Test content of foo.rb and demo.yaml files.
|
|
30
|
+
|
|
31
|
+
LONGDESC
|
|
32
|
+
def test(path_to_rb_file)
|
|
33
|
+
Project.test(path_to_rb_file, options)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rainbow'
|
|
4
|
+
|
|
5
|
+
# Class method Teuton#update
|
|
6
|
+
class Teuton < Thor
|
|
7
|
+
map ['--update', '-u', 'u'] => 'update'
|
|
8
|
+
desc 'update', 'Update TEUTON from git repo'
|
|
9
|
+
long_desc <<-LONGDESC
|
|
10
|
+
Update TEUTON project, downloading files from git repo.
|
|
11
|
+
Execute "cd PATH/TO/TEUTON/DIR && git pull".
|
|
12
|
+
|
|
13
|
+
Alias: teuton u, teuton -u, teuton --update
|
|
14
|
+
|
|
15
|
+
LONGDESC
|
|
16
|
+
def update
|
|
17
|
+
dir = File.absolute_path(File.join(File.dirname(__FILE__), '..', '..'))
|
|
18
|
+
ok = system("cd #{dir} && git pull")
|
|
19
|
+
if ok
|
|
20
|
+
puts Rainbow('[ OK ] teuton update').green.bright
|
|
21
|
+
exit(0)
|
|
22
|
+
else
|
|
23
|
+
puts Rainbow('[FAIL] teuton update').red.bright
|
|
24
|
+
exit(1)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rainbow'
|
|
4
|
+
|
|
5
|
+
# Class method Teuton#version
|
|
6
|
+
class Teuton < Thor
|
|
7
|
+
map ['v', '-v', '--version'] => 'version'
|
|
8
|
+
desc 'version', 'Show the program version'
|
|
9
|
+
def version
|
|
10
|
+
print Rainbow(Application::NAME).bright.blue
|
|
11
|
+
puts ' (version ' + Rainbow(Application::VERSION).green + ')'
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
# Functions that read data from ConfigFile using formats YAML and JSON
|
|
7
|
+
# * read
|
|
8
|
+
# * read_yaml
|
|
9
|
+
# * read_json
|
|
10
|
+
module ConfigFileReader
|
|
11
|
+
def self.read(filepath)
|
|
12
|
+
unless File.exist?(filepath)
|
|
13
|
+
data = {}
|
|
14
|
+
data[:global] = {}
|
|
15
|
+
data[:alias] = {}
|
|
16
|
+
data[:cases] = [{ tt_members: 'anonymous' }]
|
|
17
|
+
return data
|
|
18
|
+
end
|
|
19
|
+
return read_yaml(filepath) if File.extname(filepath) == '.yaml'
|
|
20
|
+
|
|
21
|
+
return read_json(filepath) if File.extname(filepath) == '.json'
|
|
22
|
+
|
|
23
|
+
raise "[ERROR] ConfigFileReader: #{filepath}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.read_yaml(filepath)
|
|
27
|
+
begin
|
|
28
|
+
data = YAML.load(File.open(filepath))
|
|
29
|
+
rescue StandardError => e
|
|
30
|
+
puts "\n" + ('=' * 80)
|
|
31
|
+
puts "[ERROR] ConfigFileReader#read <#{filepath}>"
|
|
32
|
+
puts ' I suggest to revise file format!'
|
|
33
|
+
puts " #{e.message}\n" + ('=' * 80)
|
|
34
|
+
raise "[ERROR] ConfigFileReader <#{e}>"
|
|
35
|
+
end
|
|
36
|
+
data[:global] = data[:global] || {}
|
|
37
|
+
data[:alias] = data[:alias] || {}
|
|
38
|
+
data[:cases] = data[:cases] || []
|
|
39
|
+
data
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.read_json(filepath)
|
|
43
|
+
data = JSON.parse(File.read(filepath), symbolize_names: true)
|
|
44
|
+
data[:global] = data[:global] || {}
|
|
45
|
+
data[:alias] = data[:alias] || {}
|
|
46
|
+
data[:cases] = data[:cases] || []
|
|
47
|
+
data
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
class Builtin
|
|
3
|
+
attr_accessor :param
|
|
4
|
+
|
|
5
|
+
def initialize(parent)
|
|
6
|
+
@parent = parent
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def method_missing(method)
|
|
10
|
+
@parent.log "BUILTIN #{method}"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Laboratory
|
|
15
|
+
# * service
|
|
16
|
+
class Laboratory
|
|
17
|
+
def service(param)
|
|
18
|
+
log "BUILTIN service(#{param})"
|
|
19
|
+
@builtin = @builtin || Builtin.new(self)
|
|
20
|
+
@builtin.param = param
|
|
21
|
+
@builtin
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Laboratory
|
|
2
|
+
# * target
|
|
3
|
+
# * request (development)
|
|
4
|
+
# * tempfile
|
|
5
|
+
# * goto
|
|
6
|
+
# * run
|
|
7
|
+
# * expect
|
|
8
|
+
# * get
|
|
9
|
+
# * unique
|
|
10
|
+
# * log
|
|
11
|
+
# * set
|
|
12
|
+
class Laboratory
|
|
13
|
+
def readme(_text)
|
|
14
|
+
# Usefull for "teuton reamde" action.
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def target(desc, args = {})
|
|
18
|
+
@stats[:targets] += 1
|
|
19
|
+
@targetid += 1
|
|
20
|
+
weight = args[:weight] || 1.0
|
|
21
|
+
verboseln '(%03d' % @targetid + ") target #{desc}"
|
|
22
|
+
verboseln " weight #{weight}"
|
|
23
|
+
end
|
|
24
|
+
alias goal target
|
|
25
|
+
|
|
26
|
+
def request(text)
|
|
27
|
+
@requests << text.to_s
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def tempfile(_tempfile = nil)
|
|
31
|
+
'tempfile'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def goto(host = :localhost, args = {})
|
|
35
|
+
result.reset
|
|
36
|
+
|
|
37
|
+
if @hosts[host]
|
|
38
|
+
@hosts[host] += 1
|
|
39
|
+
else
|
|
40
|
+
@hosts[host] = 1
|
|
41
|
+
end
|
|
42
|
+
verboseln " goto #{host} and #{args}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def run(command, args = {})
|
|
46
|
+
args[:exec] = command
|
|
47
|
+
goto(:localhost, args)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def expect(_cond, args = {})
|
|
51
|
+
#unless [ String, Array, Regexp].include? _cond.class
|
|
52
|
+
# verboseln "[ERROR] expect #{_cond} (#{_cond.class})"
|
|
53
|
+
# return
|
|
54
|
+
#end
|
|
55
|
+
verboseln " alter #{result.alterations}" unless result.alterations.empty?
|
|
56
|
+
#verboseln " expect #{result.expected} (#{result.expected.class})"
|
|
57
|
+
verboseln " expect #{_cond} (#{_cond.class})"
|
|
58
|
+
verboseln ''
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def expect_one(_cond, args = {})
|
|
62
|
+
verboseln " alter #{result.alterations}" unless result.alterations.empty?
|
|
63
|
+
verboseln " expect_one #{_cond} (#{_cond.class})"
|
|
64
|
+
verboseln ''
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def expect_none(_cond, args = {})
|
|
68
|
+
verboseln " alter #{result.alterations}" unless result.alterations.empty?
|
|
69
|
+
verboseln " expect_none #{_cond} (#{_cond.class})"
|
|
70
|
+
verboseln ''
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def get(varname)
|
|
74
|
+
@stats[:gets] += 1
|
|
75
|
+
|
|
76
|
+
if @gets[varname]
|
|
77
|
+
@gets[varname] += 1
|
|
78
|
+
else
|
|
79
|
+
@gets[varname] = 1
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
"get(#{varname})"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# If a method call is missing, then delegate to concept parent.
|
|
86
|
+
def method_missing(method)
|
|
87
|
+
a = method.to_s
|
|
88
|
+
instance_eval("get(:#{a[0, a.size - 1]})") if a[a.size - 1] == '?'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def gett(option)
|
|
92
|
+
value = get(option)
|
|
93
|
+
value
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def unique(key, _value)
|
|
97
|
+
@stats[:uniques] += 1
|
|
98
|
+
|
|
99
|
+
verboseln " ! Unique value for <#{key}>"
|
|
100
|
+
verboseln ''
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def log(text = '', type = :info)
|
|
104
|
+
@stats[:logs] += 1
|
|
105
|
+
verboseln " log [#{type}]: " + text.to_s
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def set(key, value)
|
|
109
|
+
@stats[:sets] += 1
|
|
110
|
+
|
|
111
|
+
key = ':' + key.to_s if key.class == Symbol
|
|
112
|
+
value = ':' + value.to_s if value.class == Symbol
|
|
113
|
+
|
|
114
|
+
@sets[key] = value
|
|
115
|
+
"set(#{key},#{value})"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'terminal-table'
|
|
4
|
+
require 'rainbow'
|
|
5
|
+
|
|
6
|
+
require_relative '../../application'
|
|
7
|
+
require_relative '../../case_manager/case/result/result'
|
|
8
|
+
require_relative 'show'
|
|
9
|
+
require_relative 'dsl'
|
|
10
|
+
require_relative 'builtin'
|
|
11
|
+
|
|
12
|
+
def use(filename)
|
|
13
|
+
filename += '.rb'
|
|
14
|
+
app = Application.instance
|
|
15
|
+
rbfiles = File.join(app.project_path, "**", filename)
|
|
16
|
+
files = Dir.glob(rbfiles)
|
|
17
|
+
use = []
|
|
18
|
+
files.sort.each { |f| use << f if f.include?(filename) }
|
|
19
|
+
require_relative use[0]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def group(name, &block)
|
|
23
|
+
Application.instance.groups << { name: name, block: block }
|
|
24
|
+
end
|
|
25
|
+
alias task group
|
|
26
|
+
|
|
27
|
+
def start(&block)
|
|
28
|
+
# don't do nothing
|
|
29
|
+
end
|
|
30
|
+
alias play start
|
|
31
|
+
|
|
32
|
+
# Show objectives stats from RB script file
|
|
33
|
+
class Laboratory
|
|
34
|
+
attr_reader :result
|
|
35
|
+
|
|
36
|
+
def initialize(script_path, config_path)
|
|
37
|
+
@path = {}
|
|
38
|
+
@path[:script] = script_path
|
|
39
|
+
@path[:dirname] = File.dirname(script_path)
|
|
40
|
+
@path[:filename] = File.basename(script_path, '.rb')
|
|
41
|
+
@path[:config] = config_path
|
|
42
|
+
reset
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def reset
|
|
46
|
+
@result = Result.new
|
|
47
|
+
@targetid = 0
|
|
48
|
+
@stats = { groups: 0, targets: 0, uniques: 0, gets: 0, logs: 0, sets: 0 }
|
|
49
|
+
@gets = {}
|
|
50
|
+
@sets = {}
|
|
51
|
+
@hosts = {}
|
|
52
|
+
@requests = []
|
|
53
|
+
@verbose = Application.instance.verbose
|
|
54
|
+
end
|
|
55
|
+
end
|