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.
@@ -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
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # Este archivo se usa para probar la ejecución del Agent
3
+ require 'bundler/setup'
4
+ require 'all_libraries'
5
+ Liri::Agent.run()
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # Este archivo se usa para probar la ejecución del Manager
3
+ require 'bundler/setup'
4
+ require 'all_libraries'
5
+ Liri::Manager.run()
@@ -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