liri 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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