liri 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rakeTasks +7 -0
- data/.rspec +8 -0
- data/.rubocop.yml +15 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +32 -0
- data/Gemfile.lock +76 -0
- data/LICENSE.txt +21 -0
- data/README.md +161 -0
- data/Rakefile +61 -0
- data/bin/bundle +114 -0
- data/bin/coderay +29 -0
- data/bin/commander +29 -0
- data/bin/htmldiff +29 -0
- data/bin/ldiff +29 -0
- data/bin/liri +29 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/bin/ruby-parse +29 -0
- data/bin/ruby-rewrite +29 -0
- data/bin/yard +29 -0
- data/bin/yardoc +29 -0
- data/bin/yri +29 -0
- data/config/locales/to_duration_es.yml +25 -0
- data/exe/liri +73 -0
- data/lib/agent/agent.rb +235 -0
- data/lib/agent/runner.rb +19 -0
- data/lib/all_libraries.rb +30 -0
- data/lib/common/benchmarking.rb +36 -0
- data/lib/common/compressor/zip.rb +70 -0
- data/lib/common/log.rb +121 -0
- data/lib/common/source_code.rb +53 -0
- data/lib/common/unit_test/rspec.rb +91 -0
- data/lib/exe/agent.rb +5 -0
- data/lib/exe/manager.rb +5 -0
- data/lib/hash_extend.rb +57 -0
- data/lib/liri.rb +129 -0
- data/lib/manager/credential.rb +47 -0
- data/lib/manager/manager.rb +258 -0
- data/lib/manager/setup.rb +70 -0
- data/lib/manager/test_result.rb +38 -0
- data/lib/task.rb +15 -0
- data/liri.gemspec +58 -0
- data/template/liri-config.yml +28 -0
- metadata +182 -0
data/lib/agent/runner.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
=begin
|
2
|
+
Esta clase se encarga de ejecutar las pruebas unitarias recibidas del Manager
|
3
|
+
=end
|
4
|
+
|
5
|
+
module Liri
|
6
|
+
class Agent
|
7
|
+
class Runner
|
8
|
+
def initialize(unit_test_class, source_code_folder_path)
|
9
|
+
@unit_test = Object.const_get(unit_test_class).new(source_code_folder_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_tests(tests)
|
13
|
+
result_hash = @unit_test.run_tests(tests.values)
|
14
|
+
result_hash[:test_keys] = tests.keys
|
15
|
+
result_hash
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# = all_libraries.rb
|
2
|
+
#
|
3
|
+
# Autor:: Rodrigo Fernández
|
4
|
+
# Web:: http://www.something.com
|
5
|
+
#
|
6
|
+
# Este archivo se encarga de importar todas las librerías a utilizar
|
7
|
+
|
8
|
+
# Se utiliza la librería *socket* de Ruby para realizar una conexión udp
|
9
|
+
require 'socket'
|
10
|
+
require 'net/ssh'
|
11
|
+
require 'net/scp'
|
12
|
+
|
13
|
+
# El archivo *hash_extend* extiende la clase Hash de Ruby para agregarle más funcionalidades
|
14
|
+
require 'hash_extend'
|
15
|
+
|
16
|
+
require 'task'
|
17
|
+
|
18
|
+
require 'agent/agent'
|
19
|
+
require 'agent/runner'
|
20
|
+
|
21
|
+
require 'common/benchmarking'
|
22
|
+
require 'common/log'
|
23
|
+
require 'common/source_code'
|
24
|
+
require 'common/compressor/zip'
|
25
|
+
require 'common/unit_test/rspec'
|
26
|
+
|
27
|
+
require 'manager/manager'
|
28
|
+
require 'manager/setup'
|
29
|
+
require 'manager/credential'
|
30
|
+
require 'manager/test_result'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# = benchmarking.rb
|
2
|
+
#
|
3
|
+
# @author Rodrigo Fernández
|
4
|
+
#
|
5
|
+
# == Módulo Benchmarking
|
6
|
+
# Este módulo se encarga de medir el tiempo de ejecución de algunos bloques de código
|
7
|
+
|
8
|
+
require 'benchmark'
|
9
|
+
require 'i18n' # requirimiento de la gema to_duration
|
10
|
+
require 'to_duration'
|
11
|
+
|
12
|
+
# Se configura la ubicación del archivo de internacionalización de la gema to_duration
|
13
|
+
I18n.load_path << Dir[File.join(File.dirname(File.dirname(File.dirname(__FILE__))), 'config/locales') + "/*.yml"]
|
14
|
+
I18n.default_locale = :es
|
15
|
+
|
16
|
+
module Liri
|
17
|
+
module Common
|
18
|
+
module Benchmarking
|
19
|
+
class << self
|
20
|
+
def start(start_msg: nil, end_msg: 'Duración: ')
|
21
|
+
print start_msg
|
22
|
+
seconds = Benchmark.realtime do
|
23
|
+
yield
|
24
|
+
end
|
25
|
+
print_result(end_msg, seconds)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def print_result(msg, seconds)
|
31
|
+
print "#{msg}#{seconds.to_duration}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
=begin
|
2
|
+
Esta clase se encarga de comprimir y descomprimir archivos
|
3
|
+
=end
|
4
|
+
require 'zip'
|
5
|
+
|
6
|
+
module Liri
|
7
|
+
module Common
|
8
|
+
module Compressor
|
9
|
+
class Zip
|
10
|
+
# Inicializa la carpeta a comprimir y la ubicación en donde se guardará el archivo comprimido
|
11
|
+
def initialize(input_dir, output_file)
|
12
|
+
@input_dir = input_dir
|
13
|
+
@output_file = output_file
|
14
|
+
end
|
15
|
+
|
16
|
+
# Comprime el directorio de entrada @input_dir en un archivo con extensión zip.
|
17
|
+
def compress
|
18
|
+
clear_output_file
|
19
|
+
entries = Dir.entries(@input_dir) - %w[. ..]
|
20
|
+
|
21
|
+
::Zip::File.open(@output_file, ::Zip::File::CREATE) do |zipfile|
|
22
|
+
write_entries(entries, '', zipfile)
|
23
|
+
end
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def decompress(zip_dir, dir_destination)
|
28
|
+
FileUtils.mkdir_p(dir_destination)
|
29
|
+
::Zip::File.open(File.expand_path(zip_dir)) do |zip_file|
|
30
|
+
zip_file.each do |f|
|
31
|
+
fpath = File.join(dir_destination, f.name)
|
32
|
+
FileUtils.mkdir_p(File.dirname(fpath))
|
33
|
+
zip_file.extract(f, fpath) unless File.exist?(fpath)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def clear_output_file
|
41
|
+
File.delete(@output_file) if File.exist?(@output_file)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Un método de ayuda que hace que la recursión funcione
|
45
|
+
def write_entries(entries, path, zipfile)
|
46
|
+
entries.each do |e|
|
47
|
+
zipfile_path = path == '' ? e : File.join(path, e)
|
48
|
+
disk_file_path = File.join(@input_dir, zipfile_path)
|
49
|
+
|
50
|
+
if File.directory? disk_file_path
|
51
|
+
recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
|
52
|
+
else
|
53
|
+
put_into_archive(disk_file_path, zipfile, zipfile_path)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
|
59
|
+
zipfile.mkdir(zipfile_path)
|
60
|
+
subdir = Dir.entries(disk_file_path) - %w[. ..]
|
61
|
+
write_entries(subdir, zipfile_path, zipfile)
|
62
|
+
end
|
63
|
+
|
64
|
+
def put_into_archive(disk_file_path, zipfile, zipfile_path)
|
65
|
+
zipfile.add(zipfile_path, disk_file_path)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/common/log.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# = log.rb
|
2
|
+
#
|
3
|
+
# @author Rodrigo Fernández
|
4
|
+
#
|
5
|
+
# == Clase Log
|
6
|
+
# Esta clase se encarga de manejar el logging
|
7
|
+
|
8
|
+
require 'logger'
|
9
|
+
|
10
|
+
module Liri
|
11
|
+
module Common
|
12
|
+
class Log
|
13
|
+
FOLDER_NAME = 'logs'
|
14
|
+
FOLDER_PATH = File.join(Dir.pwd, "/#{FOLDER_NAME}")
|
15
|
+
FILE_NAME = 'liri.log'
|
16
|
+
|
17
|
+
def initialize(shift_age, folder_path:, file_name:, stdout: true)
|
18
|
+
@stdout = stdout
|
19
|
+
@shift_age = shift_age
|
20
|
+
@folder_path = folder_path || FOLDER_PATH
|
21
|
+
@file_name = file_name || FILE_NAME
|
22
|
+
@file_path = File.join(@folder_path, '/', @file_name)
|
23
|
+
|
24
|
+
create_stdout_logger if @stdout
|
25
|
+
create_log_folder
|
26
|
+
create_file_logger
|
27
|
+
end
|
28
|
+
|
29
|
+
def debug(text)
|
30
|
+
@stdout_logger.debug(text) if @stdout
|
31
|
+
@file_logger.debug(text)
|
32
|
+
end
|
33
|
+
|
34
|
+
def info(text)
|
35
|
+
@stdout_logger.info(text) if @stdout
|
36
|
+
@file_logger.info(text)
|
37
|
+
end
|
38
|
+
|
39
|
+
def warn(text)
|
40
|
+
@stdout_logger.warn(text) if @stdout
|
41
|
+
@file_logger.warn(text)
|
42
|
+
end
|
43
|
+
|
44
|
+
def error(text)
|
45
|
+
@stdout_logger.error(text) if @stdout
|
46
|
+
@file_logger.error(text)
|
47
|
+
end
|
48
|
+
|
49
|
+
def fatal(text)
|
50
|
+
@stdout_logger.fatal(text) if @stdout
|
51
|
+
@file_logger.fatal(text)
|
52
|
+
end
|
53
|
+
|
54
|
+
def unknown(text)
|
55
|
+
@stdout_logger.unknown(text) if @stdout
|
56
|
+
@file_logger.unknown(text)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def create_stdout_logger
|
61
|
+
@stdout_logger = Logger.new(STDOUT, @shift_age)
|
62
|
+
@stdout_logger.formatter = Liri::Common::LogFormatter.colorize(Liri.setup.log.stdout.colorize)
|
63
|
+
end
|
64
|
+
|
65
|
+
def create_file_logger
|
66
|
+
@file_logger = Logger.new(@file_path, @shift_age)
|
67
|
+
@file_logger.formatter = Liri::Common::LogFormatter.colorize(Liri.setup.log.file.colorize)
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_log_folder
|
71
|
+
Dir.mkdir(@folder_path) unless Dir.exist?(@folder_path)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class LogFormatter
|
76
|
+
DATETIME_FORMAT = "%d-%m-%Y %H:%M"
|
77
|
+
|
78
|
+
SEVERITY_COLORS = {
|
79
|
+
DEBUG: '0;36', # cyan
|
80
|
+
ERROR: '0;31', # red
|
81
|
+
INFO: '0;32', # green
|
82
|
+
WARN: '0;33', # orange
|
83
|
+
FATAL: '0;35', # pink
|
84
|
+
ANY: '0;36', # cyan
|
85
|
+
DEFAULT: '1;0' # white
|
86
|
+
}
|
87
|
+
|
88
|
+
class << self
|
89
|
+
def colorize(type)
|
90
|
+
proc do |severity, datetime, progname, msg|
|
91
|
+
formatted_date = datetime.strftime(DATETIME_FORMAT)
|
92
|
+
severity_abb_block = "#{severity.slice(0)}"
|
93
|
+
date_block = "[#{formatted_date}##{Process.pid}]"
|
94
|
+
severity_block = "#{severity} -- :"
|
95
|
+
msg_block = "#{msg}\n"
|
96
|
+
|
97
|
+
case type
|
98
|
+
when 'severity' then
|
99
|
+
info_block = "#{colorize_according_severity(severity, severity_abb_block)} #{date_block} #{colorize_according_severity(severity, severity_block)}"
|
100
|
+
when 'severity_date' then
|
101
|
+
info_block = colorize_according_severity(severity, "#{severity_abb_block} #{date_block} #{severity_block}")
|
102
|
+
when 'full' then
|
103
|
+
info_block = colorize_according_severity(severity, "#{severity_abb_block} #{date_block} #{severity_block}")
|
104
|
+
msg_block = colorize_according_severity(severity, msg_block)
|
105
|
+
else
|
106
|
+
info_block = "#{severity_abb_block} #{date_block} #{severity_block}"
|
107
|
+
end
|
108
|
+
|
109
|
+
"#{info_block} #{msg_block}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
def colorize_according_severity(severity, line)
|
115
|
+
color = SEVERITY_COLORS[severity.to_sym] || SEVERITY_COLORS[:DEFAULT]
|
116
|
+
"\e[#{color}m#{line}\e[0m"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
=begin
|
2
|
+
Este clase se encarga de manejar lo relativo al código fuente
|
3
|
+
=end
|
4
|
+
|
5
|
+
module Liri
|
6
|
+
module Common
|
7
|
+
class SourceCode
|
8
|
+
FOLDER_PATH = Dir.pwd
|
9
|
+
FOLDER_NAME = FOLDER_PATH.split('/').last
|
10
|
+
DECOMPRESSED_FOLDER_NAME = 'decompressed'
|
11
|
+
attr_reader :compressed_file_folder_path, :compressed_file_path, :decompressed_file_folder_path
|
12
|
+
|
13
|
+
def initialize(compressed_file_folder_path, compression_class, unit_test_class)
|
14
|
+
@compressed_file_folder_path = compressed_file_folder_path
|
15
|
+
@decompressed_file_folder_path = File.join(@compressed_file_folder_path, '/', DECOMPRESSED_FOLDER_NAME)
|
16
|
+
@compressed_file_path = File.join(@compressed_file_folder_path, '/', "#{FOLDER_NAME}.zip")
|
17
|
+
# Inicializa un compresor acorde a compression_class, la siguiente línea en realidad hace lo siguiente:
|
18
|
+
# @compressor = Liri::Common::Compressor::Zip.new(input_dir, output_file)
|
19
|
+
# compression_class en este caso es Zip pero podría ser otro si existiera la implementación, por ejemplo Rar
|
20
|
+
@compressor = Object.const_get(compression_class).new(FOLDER_PATH, @compressed_file_path)
|
21
|
+
# Inicializa un ejecutor de pruebas acorde a unit_test_class, la siguiente línea en realidad hace lo siguiente:
|
22
|
+
# @unit_test = Liri::Common::UnitTest::Rspec.new(source_code_folder_path)
|
23
|
+
# unit_test_class en este caso es Rspec pero podría ser otro si existiera la implementación, por ejemplo UnitTest
|
24
|
+
@unit_test = Object.const_get(unit_test_class).new(FOLDER_PATH)
|
25
|
+
end
|
26
|
+
|
27
|
+
def compress_folder
|
28
|
+
@compressor.compress
|
29
|
+
end
|
30
|
+
|
31
|
+
def decompress_file(compressed_file_path = @compressed_file_path)
|
32
|
+
@compressor.decompress(compressed_file_path, @decompressed_file_folder_path)
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete_compressed_file
|
36
|
+
if File.exist?(@compressed_file_path)
|
37
|
+
File.delete(@compressed_file_path)
|
38
|
+
true
|
39
|
+
else
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def all_tests
|
45
|
+
@unit_test.all_tests
|
46
|
+
end
|
47
|
+
|
48
|
+
def folder_path
|
49
|
+
FOLDER_PATH
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Liri
|
2
|
+
module Common
|
3
|
+
module UnitTest
|
4
|
+
class Rspec
|
5
|
+
TESTS_FOLDER_NAME = 'spec'
|
6
|
+
attr_reader :tests_folder_path
|
7
|
+
|
8
|
+
def initialize(source_code_folder_path)
|
9
|
+
@source_code_folder_path = source_code_folder_path
|
10
|
+
@tests_folder_path = File.join(source_code_folder_path, TESTS_FOLDER_NAME)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Retorna un hash con todos los tests. Ex.: {1=>"spec/hash_spec.rb:2", 2=>"spec/hash_spec.rb:13", 3=>"spec/hash_spec.rb:24", ..., 29=>"spec/liri_spec.rb:62"}
|
14
|
+
def all_tests
|
15
|
+
tests_count = 1
|
16
|
+
tests_hash = {}
|
17
|
+
test_files.each do |test_file|
|
18
|
+
File.open(test_file) do |file|
|
19
|
+
file.each_with_index do |line, index|
|
20
|
+
if line.strip.start_with?('it')
|
21
|
+
absolute_file_path = file.to_path
|
22
|
+
relative_file_path = absolute_file_path.sub(@source_code_folder_path + '/', '')
|
23
|
+
|
24
|
+
test_line = relative_file_path + ":#{index + 1}"
|
25
|
+
tests_hash[tests_count] = test_line
|
26
|
+
tests_count += 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
tests_hash
|
32
|
+
end
|
33
|
+
|
34
|
+
# Recibe un arreglo de rutas a las pruebas unitarias
|
35
|
+
# Ejecuta las pruebas unitarias y retorna el resultado como un hash
|
36
|
+
def run_tests(tests)
|
37
|
+
# Se puede ejecutar comandos en líneas de comandos usando system(cli_command) o %x|cli_command|
|
38
|
+
# system devuelve true, false o nil, %x devuelve la salida del comando ejecutado
|
39
|
+
# From:
|
40
|
+
# https://www.rubyguides.com/2018/12/ruby-system/
|
41
|
+
|
42
|
+
#system("bundle exec rspec #{tests_paths} --format progress --out rspec_result.txt --no-color")
|
43
|
+
# El comando chdir hace que el directorio de trabajo se mueva a la carpeta en donde se descomprimió el código fuente para poder ejecutar las pruebas
|
44
|
+
Dir.chdir(@source_code_folder_path) do
|
45
|
+
# Descomentar para la depuración en entorno de desarrollo (Creo que aún así no se puede depurar)
|
46
|
+
# raw_tests_result = %x|bundle exec rspec #{tests.join(' ')} --format progress|
|
47
|
+
# Descomentar para el entorno de producción
|
48
|
+
raw_tests_result = ''
|
49
|
+
Liri::Common::Benchmarking.start(start_msg: "Ejecutando conjunto de pruebas. Espere... ") do
|
50
|
+
raw_tests_result = %x|bash -lc 'rvm use #{Liri.current_folder_ruby_and_gemset}; rspec #{tests.join(' ')} --format progress'|
|
51
|
+
end
|
52
|
+
|
53
|
+
hash_tests_result = process_tests_result(raw_tests_result)
|
54
|
+
hash_tests_result
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def test_files
|
60
|
+
Dir[@tests_folder_path + "/**/*spec.rb"]
|
61
|
+
end
|
62
|
+
|
63
|
+
# Recibe el resultado crudo de las pruebas unitarias
|
64
|
+
# Procesa el resultado y lo devuelve en formato hash manejable
|
65
|
+
# Ejemplo del hash retornado:
|
66
|
+
# {example_quantity: 2, failure_quantity: 1}
|
67
|
+
def process_tests_result(raw_test_results)
|
68
|
+
result_hash = {example_quantity: 0, failure_quantity: 0}
|
69
|
+
flag = ''
|
70
|
+
raw_test_results.each_line do |line|
|
71
|
+
if line.strip.start_with?('Finished')
|
72
|
+
flag = 'Finished'
|
73
|
+
next
|
74
|
+
end
|
75
|
+
|
76
|
+
if flag == 'Finished'
|
77
|
+
puts ''
|
78
|
+
Liri.logger.info(line)
|
79
|
+
values = line.to_s.match(/([\d]+) example.?, ([\d]+) failure.?/)
|
80
|
+
result_hash[:example_quantity] = values[1].to_i
|
81
|
+
result_hash[:failure_quantity] = values[2].to_i
|
82
|
+
flag = ''
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
result_hash
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/exe/agent.rb
ADDED
data/lib/exe/manager.rb
ADDED
data/lib/hash_extend.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# = hash_extend.rb
|
2
|
+
#
|
3
|
+
# @author Rodrigo Fernández
|
4
|
+
#
|
5
|
+
# == Clase Hash
|
6
|
+
# Esta clase extiende las funcionalidades de la clase Hash de Ruby
|
7
|
+
class Hash
|
8
|
+
# Retorna un hash con elementos aleatorios del hash original.
|
9
|
+
# @param quantity [Integer] la cantidad de elementos del nuevo hash retornado.
|
10
|
+
# @return [Hash] un hash con elementos aleatorios del hash original.
|
11
|
+
# @example
|
12
|
+
# hash = {uno: 'uno', dos: 'dos', tres: 'tres'}
|
13
|
+
# hash.sample
|
14
|
+
# => {dos: 'dos'}
|
15
|
+
# hash.sample(2)
|
16
|
+
# => {uno: 'uno', tres: 'tres'}
|
17
|
+
def sample(quantity=1)
|
18
|
+
sample_keys = self.keys.sample(quantity)
|
19
|
+
sample_values = {}
|
20
|
+
sample_keys.each do |sample_key|
|
21
|
+
sample_values[sample_key] = self[sample_key]
|
22
|
+
end
|
23
|
+
sample_values
|
24
|
+
end
|
25
|
+
|
26
|
+
# Retorna un hash con elementos aleatorios del hash original y borra estos elementos del hash.
|
27
|
+
# @param quantity [Integer] la cantidad de elementos del nuevo hash retornado.
|
28
|
+
# @return [Hash] un hash con elementos aleatorios del hash original.
|
29
|
+
# @example
|
30
|
+
# hash = {uno: 'uno', dos: 'dos', tres: 'tres'}
|
31
|
+
# hash.sample
|
32
|
+
# => {dos: 'dos'}
|
33
|
+
# hash.sample(2)
|
34
|
+
# => {uno: 'uno', tres: 'tres'}
|
35
|
+
def sample!(quantity=1)
|
36
|
+
samples = self.sample(quantity)
|
37
|
+
remove!(samples.keys)
|
38
|
+
samples
|
39
|
+
end
|
40
|
+
|
41
|
+
# Borra elementos del hash.
|
42
|
+
# @note Los elementos son borrados del hash original
|
43
|
+
# @param keys [Array] las claves a remover separadas por comas o en un arreglo.
|
44
|
+
# @return [Hash] un hash sin los elementos indicados.
|
45
|
+
# @example
|
46
|
+
# hash = {uno: 'uno', dos: 'dos', tres: 'tres'}
|
47
|
+
# hash.remove!(:uno)
|
48
|
+
# => {:dos=>"dos", :tres=>"tres"}
|
49
|
+
# hash.remove!(:uno, :dos, :tres)
|
50
|
+
# => {}
|
51
|
+
# hash
|
52
|
+
# => {}
|
53
|
+
def remove!(*keys)
|
54
|
+
keys.flatten.each{|key| self.delete(key) }
|
55
|
+
self
|
56
|
+
end
|
57
|
+
end
|
data/lib/liri.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Este modulo contiene datos del programa que son reutilizados en otras partes de la aplicacion
|
4
|
+
module Liri
|
5
|
+
NAME = 'liri' # El gemspec requiere que el nombre este en minusculas
|
6
|
+
VERSION = '0.1.0'
|
7
|
+
SETUP_FOLDER_NAME = 'liri'
|
8
|
+
SETUP_FOLDER_PATH = File.join(Dir.pwd, '/', SETUP_FOLDER_NAME)
|
9
|
+
LOGS_FOLDER_NAME = 'logs'
|
10
|
+
MANAGER_LOGS_FOLDER_PATH = File.join(SETUP_FOLDER_PATH, '/', LOGS_FOLDER_NAME)
|
11
|
+
AGENT_LOGS_FOLDER_PATH = MANAGER_LOGS_FOLDER_PATH
|
12
|
+
AGENT_FOLDER_NAME = 'agent'
|
13
|
+
AGENT_FOLDER_PATH = File.join(SETUP_FOLDER_PATH, '/', AGENT_FOLDER_NAME)
|
14
|
+
MANAGER_FOLDER_NAME = 'manager'
|
15
|
+
MANAGER_FOLDER_PATH = File.join(SETUP_FOLDER_PATH, '/', MANAGER_FOLDER_NAME)
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def setup
|
19
|
+
@setup ||= load_setup
|
20
|
+
end
|
21
|
+
|
22
|
+
def logger
|
23
|
+
@logger ||= load_logger
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_logger(folder_path, file_name)
|
27
|
+
@logger = load_logger(folder_path, file_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def clear_setup
|
31
|
+
if @setup
|
32
|
+
@setup = nil
|
33
|
+
true
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_folders(program)
|
40
|
+
Dir.mkdir(SETUP_FOLDER_PATH) unless Dir.exist?(SETUP_FOLDER_PATH)
|
41
|
+
|
42
|
+
case program
|
43
|
+
when 'manager'
|
44
|
+
Dir.mkdir(MANAGER_LOGS_FOLDER_PATH) unless Dir.exist?(MANAGER_LOGS_FOLDER_PATH)
|
45
|
+
Dir.mkdir(MANAGER_FOLDER_PATH) unless Dir.exist?(MANAGER_FOLDER_PATH)
|
46
|
+
when 'agent'
|
47
|
+
Dir.mkdir(AGENT_FOLDER_PATH) unless Dir.exist?(AGENT_FOLDER_PATH)
|
48
|
+
Dir.mkdir(AGENT_LOGS_FOLDER_PATH) unless Dir.exist?(AGENT_LOGS_FOLDER_PATH)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def clean_folder(folder_path)
|
53
|
+
FileUtils.rm_rf(Dir.glob(folder_path + '/*')) if Dir.exist?(folder_path)
|
54
|
+
end
|
55
|
+
|
56
|
+
def reload_setup
|
57
|
+
@setup = load_setup
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete_setup
|
61
|
+
liri_setup = Liri::Manager::Setup.new(SETUP_FOLDER_PATH)
|
62
|
+
liri_setup.delete
|
63
|
+
end
|
64
|
+
|
65
|
+
def init_exit(stop, threads, program)
|
66
|
+
threads = threads.compact
|
67
|
+
kill(threads) if stop
|
68
|
+
|
69
|
+
# Con la siguiente línea se asegura que los hilos no mueran antes de que finalize el programa principal
|
70
|
+
# Fuente: https://underc0de.org/foro/ruby/hilos-en-ruby/
|
71
|
+
threads.each{|thread| thread.join}
|
72
|
+
#rescue SignalException => e
|
73
|
+
#puts "\nEjecución del #{program} terminada manualmente\n"
|
74
|
+
#kill(threads)
|
75
|
+
end
|
76
|
+
|
77
|
+
def kill(threads)
|
78
|
+
threads.each{|thread| Thread.kill(thread)}
|
79
|
+
end
|
80
|
+
|
81
|
+
def current_host_ip_address
|
82
|
+
addr = Socket.ip_address_list.select(&:ipv4?).detect{|addr| addr.ip_address != '127.0.0.1'}
|
83
|
+
addr.ip_address
|
84
|
+
end
|
85
|
+
|
86
|
+
def compression_class
|
87
|
+
"Liri::Common::Compressor::#{setup.library.compression}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def unit_test_class
|
91
|
+
"Liri::Common::UnitTest::#{setup.library.unit_test}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def udp_port
|
95
|
+
setup.ports.udp
|
96
|
+
end
|
97
|
+
|
98
|
+
def tcp_port
|
99
|
+
setup.ports.tcp
|
100
|
+
end
|
101
|
+
|
102
|
+
def current_folder_ruby_and_gemset
|
103
|
+
"#{File.read('.ruby-version').strip}@#{File.read('.ruby-gemset').strip}"
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
# Carga las configuraciones en memoria desde un archivo de configuracion
|
109
|
+
def load_setup
|
110
|
+
liri_setup = Liri::Manager::Setup.new(SETUP_FOLDER_PATH)
|
111
|
+
liri_setup.create unless File.exist?(liri_setup.path)
|
112
|
+
liri_setup.load
|
113
|
+
end
|
114
|
+
|
115
|
+
# Inicializa y configura la librería encargada de loguear
|
116
|
+
def load_logger(folder_path = nil, file_name = nil)
|
117
|
+
log = Liri::Common::Log.new('daily', folder_path: folder_path, file_name: file_name, stdout: Liri.setup.log.stdout.show)
|
118
|
+
log
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# EXCEPTIONS
|
123
|
+
class FileNotFoundError < StandardError
|
124
|
+
def initialize(file_path)
|
125
|
+
msg = "No se encuentra el archivo #{file_path}"
|
126
|
+
super(msg)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'highline/import'
|
2
|
+
|
3
|
+
module Liri
|
4
|
+
class Manager
|
5
|
+
class Credential
|
6
|
+
FILE_NAME = 'liri-credentials.yml'
|
7
|
+
def initialize(folder_path)
|
8
|
+
@folder_path = folder_path
|
9
|
+
@file_path = File.join(@folder_path, '/', FILE_NAME)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Obtiene ususario y contraseña del sistema en el que se ejecuta el programa
|
13
|
+
def get
|
14
|
+
user, password = get_credentials
|
15
|
+
unless user || password
|
16
|
+
user, password = ask_credentials
|
17
|
+
save_credentials(user, password)
|
18
|
+
end
|
19
|
+
return user, password
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def get_local_user
|
24
|
+
%x[whoami].delete!("\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_credentials
|
28
|
+
if File.exist?(@file_path)
|
29
|
+
data = YAML.load(File.read(@file_path))
|
30
|
+
return data['user'], data['password']
|
31
|
+
else
|
32
|
+
return nil, nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def ask_credentials
|
37
|
+
local_user = get_local_user
|
38
|
+
password = ask("Ingrese contraseña del usuario #{local_user}: ") { |q| q.echo = "*" }
|
39
|
+
return local_user, password
|
40
|
+
end
|
41
|
+
|
42
|
+
def save_credentials(user, password)
|
43
|
+
File.write(@file_path, "user: #{user}\npassword: #{password}")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|