blufin-lib 1.4.0 → 1.5.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 +4 -4
- data/lib/blufin-lib.rb +14 -18
- data/lib/{blufin-lib/core → core}/arrays.rb +0 -0
- data/lib/{blufin-lib/core → core}/browser.rb +0 -0
- data/lib/{blufin-lib/core → core}/datetime_utils.rb +0 -0
- data/lib/{blufin-lib/core → core}/encryptor.rb +0 -0
- data/lib/{blufin-lib/core → core}/files.rb +29 -19
- data/lib/core/image.rb +152 -0
- data/lib/{blufin-lib/core → core}/network.rb +1 -7
- data/lib/{blufin-lib/core → core}/numbers.rb +0 -0
- data/lib/{blufin-lib/core → core}/routes.rb +0 -0
- data/lib/{blufin-lib/core → core}/ssh.rb +0 -0
- data/lib/{blufin-lib/core → core}/strings.rb +0 -0
- data/lib/{blufin-lib/core → core}/terminal.rb +223 -27
- data/lib/{blufin-lib/core → core}/tools.rb +0 -0
- data/lib/core/validate.rb +51 -0
- data/lib/version.rb +1 -1
- metadata +32 -17
- data/lib/blufin-lib/test/TestEnvironmentValidator.rb +0 -98
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 781d11b53064e1a5a3dea7d33e7a9d991dd0b7ee
|
4
|
+
data.tar.gz: 4ba21e3918b587754588ca52f4a457885597c68c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c0cd453d915027c66fc137f0346ed9d19fccfc72de22ce75e6535b1edefc929f16ee2c6af11571d27219f043c6af1c0c7fa5d3d82c2216c61818b626e1735b8
|
7
|
+
data.tar.gz: 49d99beb71dedc4a3b8f09bf792f4b1e1fcd552a2598499d60eafc394420b59af100759c44a35612064c4d4dde490e6d73fc83c7b546f149bc10bb6d020d95f3
|
data/lib/blufin-lib.rb
CHANGED
@@ -1,22 +1,18 @@
|
|
1
1
|
module Blufin
|
2
2
|
|
3
|
-
autoload :Arrays, '
|
4
|
-
autoload :Browser, '
|
5
|
-
autoload :DateTimeUtils, '
|
6
|
-
autoload :Encryptor, '
|
7
|
-
autoload :Files, '
|
8
|
-
autoload :
|
9
|
-
autoload :
|
10
|
-
autoload :
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
autoload :
|
14
|
-
autoload :
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
autoload :EnvironmentValidator, 'blufin-lib/test/TestEnvironmentValidator'
|
19
|
-
|
20
|
-
end
|
3
|
+
autoload :Arrays, 'core/arrays'
|
4
|
+
autoload :Browser, 'core/browser'
|
5
|
+
autoload :DateTimeUtils, 'core/datetime_utils'
|
6
|
+
autoload :Encryptor, 'core/encryptor'
|
7
|
+
autoload :Files, 'core/files'
|
8
|
+
autoload :Image, 'core/image'
|
9
|
+
autoload :Network, 'core/network'
|
10
|
+
autoload :Numbers, 'core/numbers'
|
11
|
+
autoload :Routes, 'core/routes'
|
12
|
+
autoload :SSH, 'core/ssh'
|
13
|
+
autoload :Strings, 'core/strings'
|
14
|
+
autoload :Terminal, 'core/terminal'
|
15
|
+
autoload :Tools, 'core/tools'
|
16
|
+
autoload :Validate, 'core/validate'
|
21
17
|
|
22
18
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -12,7 +12,7 @@ module Blufin
|
|
12
12
|
# will sort the import statements in the same order as IntelliJ would.
|
13
13
|
# @return String
|
14
14
|
def self.write_file_java(path_and_file, array_of_lines, auto_generated = JAVA_AUTO_GENERATED_EVERY_RUN)
|
15
|
-
raise RuntimeError, "Expected String, instead got
|
15
|
+
raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
|
16
16
|
auto_generated_valid = [JAVA_AUTO_GENERATED_EVERY_RUN, JAVA_AUTO_GENERATED_ONCE]
|
17
17
|
raise RuntimeError, "Expected .java file, instead got: #{path_and_file}" unless path_and_file =~ /\.java\z/
|
18
18
|
raise RuntimeError, "auto_generated must be one of the following: #{auto_generated_valid.join(', ')}" unless auto_generated_valid.include?(auto_generated)
|
@@ -160,7 +160,7 @@ module Blufin
|
|
160
160
|
# Write an "Array of Lines" to a file -- overwrites file if exists!
|
161
161
|
# @return String
|
162
162
|
def self.write_file(path_and_file, array_of_lines)
|
163
|
-
raise RuntimeError, "Expected String, instead got
|
163
|
+
raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
|
164
164
|
path_and_file = File.expand_path(path_and_file)
|
165
165
|
raise RuntimeError, "Expected an array of lines to write to file, instead got: #{array_of_lines.class}" unless array_of_lines.is_a? Array
|
166
166
|
prepare_for_file_write(path_and_file)
|
@@ -184,7 +184,7 @@ module Blufin
|
|
184
184
|
# Write a "String" to a file -- overwrites file if exists!
|
185
185
|
# @return void
|
186
186
|
def self.write_file_string(path_and_file, content)
|
187
|
-
raise RuntimeError, "Expected String, instead got
|
187
|
+
raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
|
188
188
|
path_and_file = File.expand_path(path_and_file)
|
189
189
|
raise RuntimeError, "Expected String to write to file, instead got: #{content.class}" unless content.is_a? String
|
190
190
|
prepare_for_file_write(path_and_file)
|
@@ -204,7 +204,7 @@ module Blufin
|
|
204
204
|
# replace -> If TRUE, will replace file rather than writing on next line after regex.
|
205
205
|
# @return void
|
206
206
|
def self.write_line_to_file(path_and_file, line, regex = nil, only_if_not_exists = true, replace = false)
|
207
|
-
raise RuntimeError, "Expected String, instead got
|
207
|
+
raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
|
208
208
|
path_and_file = File.expand_path(path_and_file)
|
209
209
|
raise RuntimeError, "File not found: #{path_and_file}" unless file_exists(path_and_file)
|
210
210
|
raise RuntimeError, "Expected String to write to file, instead got: #{line.class}" unless line.is_a? String
|
@@ -252,7 +252,7 @@ module Blufin
|
|
252
252
|
# multiple_occurrences -> If set to TRUE, will remove ALL occurrences from file.
|
253
253
|
# @return void
|
254
254
|
def self.remove_line_from_file(path_and_file, regex, multiple_occurrences = false)
|
255
|
-
raise RuntimeError, "Expected String, instead got
|
255
|
+
raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
|
256
256
|
path_and_file = File.expand_path(path_and_file)
|
257
257
|
raise RuntimeError, "Expected Regexp to match to line, instead got: #{regex.class}" unless regex.is_a? Regexp
|
258
258
|
raise RuntimeError, "File not found: #{path_and_file}" unless file_exists(path_and_file)
|
@@ -279,7 +279,7 @@ module Blufin
|
|
279
279
|
# Get content of a file as an "Array of Lines"
|
280
280
|
# @return Array
|
281
281
|
def self.read_file(path_and_file, start_line = nil, end_line = nil)
|
282
|
-
raise RuntimeError, "Expected String, instead got
|
282
|
+
raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
|
283
283
|
line_count = 0
|
284
284
|
path_and_file = File.expand_path(path_and_file)
|
285
285
|
raise RuntimeError, "File not found: #{path_and_file}" unless file_exists(path_and_file)
|
@@ -299,45 +299,38 @@ module Blufin
|
|
299
299
|
# Deletes a file (if exists)
|
300
300
|
# @return void
|
301
301
|
def self.delete_file(path_and_file)
|
302
|
-
raise RuntimeError, "Expected String, instead got
|
302
|
+
raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
|
303
303
|
FileUtils.rm(File.expand_path(path_and_file)) if file_exists(path_and_file)
|
304
304
|
end
|
305
305
|
|
306
306
|
# Returns TRUE or FALSE depending whether a path exists.
|
307
307
|
# @return void
|
308
308
|
def self.path_exists(path)
|
309
|
-
raise RuntimeError, "Expected String, instead got
|
309
|
+
raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String)
|
310
310
|
File.directory?(File.expand_path(path))
|
311
311
|
end
|
312
312
|
|
313
313
|
# Returns TRUE or FALSE depending whether a path exists.
|
314
314
|
# @return void
|
315
315
|
def self.file_exists(path_and_file)
|
316
|
-
raise RuntimeError, "Expected String, instead got
|
316
|
+
raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
|
317
317
|
File.exist?(File.expand_path(path_and_file))
|
318
318
|
end
|
319
319
|
|
320
|
-
# Get full path, IE: '~/Repos' would become '/Users/Albert/Repos'
|
321
|
-
# @return String
|
322
|
-
def self.get_full_path(path)
|
323
|
-
raise RuntimeError, "Expected String, instead got:#{path.class}" unless path.is_a?(String)
|
324
|
-
"/#{Blufin::Strings.remove_surrounding_slashes(File.expand_path(path))}"
|
325
|
-
end
|
326
|
-
|
327
320
|
# Get and array of files in a directory.
|
328
321
|
# @return Array
|
329
322
|
def self.get_files_in_dir(path, only_with_extension = nil)
|
330
|
-
raise RuntimeError, "Expected String, instead got
|
323
|
+
raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String)
|
331
324
|
path = "/#{Blufin::Strings.remove_surrounding_slashes(File.expand_path(path))}"
|
332
325
|
raise RuntimeError, "Directory doesn't exist: #{path}" unless path_exists(path)
|
333
326
|
files = Dir.glob("#{path}/**/*.#{only_with_extension.nil? ? '*' : only_with_extension}")
|
334
327
|
files.uniq.sort
|
335
328
|
end
|
336
329
|
|
337
|
-
|
330
|
+
# Get and array of directories in a directory.
|
338
331
|
# @return Array
|
339
332
|
def self.get_dirs_in_dir(path, recursive = false)
|
340
|
-
raise RuntimeError, "Expected String, instead got
|
333
|
+
raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String)
|
341
334
|
path = "/#{Blufin::Strings.remove_surrounding_slashes(File.expand_path(path))}"
|
342
335
|
raise RuntimeError, "Directory doesn't exist: #{path}" unless path_exists(path)
|
343
336
|
dirs = Dir.glob("#{path}/**/*/")
|
@@ -350,6 +343,8 @@ module Blufin
|
|
350
343
|
dirs = root_dirs
|
351
344
|
end
|
352
345
|
dirs.map! { |value| value.gsub(/\/\z/, '') }
|
346
|
+
dirs.uniq!
|
347
|
+
dirs.sort!
|
353
348
|
dirs
|
354
349
|
end
|
355
350
|
|
@@ -371,6 +366,21 @@ module Blufin
|
|
371
366
|
create_directory(path)
|
372
367
|
end
|
373
368
|
|
369
|
+
# Get the path name ONLY (from a full path).
|
370
|
+
# @return string
|
371
|
+
def self.extract_path_name(path_and_file)
|
372
|
+
raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
|
373
|
+
File.dirname(File.expand_path(path_and_file))
|
374
|
+
end
|
375
|
+
|
376
|
+
# Get the file name ONLY (from a full path).
|
377
|
+
# @return string
|
378
|
+
def self.extract_file_name(path_and_file, include_extension = true)
|
379
|
+
raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
|
380
|
+
return File.basename(File.expand_path(path_and_file)) if include_extension
|
381
|
+
return File.basename(File.expand_path(path_and_file), '*') unless include_extension
|
382
|
+
end
|
383
|
+
|
374
384
|
private
|
375
385
|
|
376
386
|
# Creates path (if not exists) and deletes file (if exists).
|
data/lib/core/image.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'mini_magick'
|
2
|
+
require 'filesize'
|
3
|
+
|
4
|
+
module Blufin
|
5
|
+
|
6
|
+
class ImageContainer
|
7
|
+
attr_accessor :width, :height, :size, :size_human, :type, :ratio
|
8
|
+
end
|
9
|
+
|
10
|
+
class Image
|
11
|
+
|
12
|
+
VALID_SIDES = %w(width height)
|
13
|
+
|
14
|
+
# Uses ImageMagick to return details about an image.
|
15
|
+
# @return Hash
|
16
|
+
def self.info(path_and_file)
|
17
|
+
check_image_magick_installed
|
18
|
+
raise RuntimeError, "File not found: #{path_and_file}" unless Blufin::Files::file_exists(path_and_file)
|
19
|
+
img = MiniMagick::Image.open(path_and_file)
|
20
|
+
img_container = ImageContainer.new
|
21
|
+
img_container.width = img.dimensions[0].to_i
|
22
|
+
img_container.height = img.dimensions[1].to_i
|
23
|
+
img_container.size = img.size
|
24
|
+
img_container.size_human = img.human_size
|
25
|
+
img_container.type = img.type.downcase
|
26
|
+
img_container.ratio = calc_aspect_ratio(img.dimensions[0].to_i, img.dimensions[1].to_i)
|
27
|
+
img_container
|
28
|
+
end
|
29
|
+
|
30
|
+
# This command crops an image based on a give size and a ration (using ImageMagick).
|
31
|
+
# If dimensions don't match ratio, adjusts accordingly and crops from center.
|
32
|
+
# Must specify if you want @side to be width or height, where your chosen side will match @length and the other gets altered as needed.
|
33
|
+
# @src - path/file to source image.
|
34
|
+
# @target - path/file to target image.
|
35
|
+
# side - the side for which you want to apply the length to (other side will get adjusted accordingly)
|
36
|
+
# length - the length that you want applied
|
37
|
+
# ratio - the ratio you want (16:9 and 9:16 will produce different results)
|
38
|
+
# quality - the higher the quality, the bigger the image.
|
39
|
+
# @return void
|
40
|
+
def self.crop_to_length_and_ratio(src, target, side, length, ratio, quality = 100)
|
41
|
+
d1 = length
|
42
|
+
side.downcase!
|
43
|
+
raise RuntimeError, "Expected integer, instead got: #{d1}" unless d1.to_s =~ /^\d+$/
|
44
|
+
raise RuntimeError, "Expected one of: #{VALID_SIDES.inspect}, instead got: #{side}" unless VALID_SIDES.include?(side)
|
45
|
+
raise RuntimeError, "Unexpected ratio #{Blufin::Terminal::format_highlight(ratio)}, expected something like: 16:9" unless ratio =~ /\d{1,2}:\d{1,2}/
|
46
|
+
raise RuntimeError, "Expected integer between 0 - 100, instead got: #{quality}" unless quality.to_s =~ /^\d+$/ && quality.to_i >= 0 && quality.to_i <= 100
|
47
|
+
raise RuntimeError, "File not found: #{src}" unless Blufin::Files::file_exists(src)
|
48
|
+
# Convert the initial image to match the width.
|
49
|
+
c1 = side == 'width' ? d1 : "x#{d1}"
|
50
|
+
Blufin::Terminal::execute("magick #{src} -resize #{c1} -quality #{quality} #{target}")
|
51
|
+
ac = info(target)
|
52
|
+
d2 = side == 'width' ? calc_height_from_ratio(ratio, d1) : calc_width_from_ratio(ratio, d1)
|
53
|
+
# If the other side is less that what's desired, convert the image using the other orientation.
|
54
|
+
c3 = side == 'width' ? ac.height : ac.width
|
55
|
+
if c3 < d2
|
56
|
+
c2 = side == 'width' ? "x#{d2}" : d2
|
57
|
+
Blufin::Terminal::execute("magick #{src} -resize #{c2} -quality #{quality} #{target}")
|
58
|
+
ac = info(target)
|
59
|
+
end
|
60
|
+
ow = ac.width
|
61
|
+
oh = ac.height
|
62
|
+
if side == 'width'
|
63
|
+
x = ow > d1 ? ((ow - d1) / 2).to_i : 0
|
64
|
+
y = oh > d2 ? ((oh - d2) / 2).to_i : 0
|
65
|
+
c4 = d1
|
66
|
+
c5 = calc_height_from_ratio(ratio, d1)
|
67
|
+
else
|
68
|
+
x = ow > d2 ? ((ow - d2) / 2).to_i : 0
|
69
|
+
y = oh > d1 ? ((oh - d1) / 2).to_i : 0
|
70
|
+
c4 = calc_width_from_ratio(ratio, d1)
|
71
|
+
c5 = d1
|
72
|
+
end
|
73
|
+
# Do the final crop.
|
74
|
+
Blufin::Terminal::execute("convert #{target} -crop #{c4}x#{c5}+#{x}+#{y} +repage #{target}")
|
75
|
+
# Output details about the image.
|
76
|
+
img = info(target)
|
77
|
+
ts = target.split('/')
|
78
|
+
puts
|
79
|
+
puts " \x1B[38;5;40m#{ts[ts.length - 1]}\x1B[38;5;240m \xe2\x80\x94 #{Filesize.from("#{img.size} B").pretty} | #{img.ratio}#{img.ratio != ratio ? ' - For this image, a perfect ratio couldn\'t be achieved :(' : nil}\x1B[0m"
|
80
|
+
puts
|
81
|
+
end
|
82
|
+
|
83
|
+
# Adds text/caption to image.
|
84
|
+
# @return void
|
85
|
+
def self.add_text(src, target, text, x = 35, y = 60, bg = 'black', fg = 'white', point_size = 22, stroke_width = 1)
|
86
|
+
raise RuntimeError, "File not found: #{src}" unless Blufin::Files::file_exists(src)
|
87
|
+
raise RuntimeError, "Expected integer (for x), instead got: #{x}" unless x.to_s =~ /^\d+$/
|
88
|
+
raise RuntimeError, "Expected integer (for y), instead got: #{y}" unless y.to_s =~ /^\d+$/
|
89
|
+
raise RuntimeError, "Expected integer (for point_size), instead got: #{point_size}" unless point_size.to_s =~ /^\d+$/
|
90
|
+
raise RuntimeError, "Expected integer (for stroke_width), instead got: #{stroke_width}" unless stroke_width.to_s =~ /^\d+$/
|
91
|
+
Blufin::Terminal::execute("convert #{src} -undercolor #{bg} -stroke #{fg} -pointsize #{point_size} -strokewidth #{stroke_width} -draw \"text #{x},#{y} '#{text}'\" #{target}")
|
92
|
+
end
|
93
|
+
|
94
|
+
# Calculates the aspect ration (IE: 16:9) from a set of given dimensions.
|
95
|
+
# @return string
|
96
|
+
def self.calc_aspect_ratio(width, height)
|
97
|
+
gcd = gcd(width, height)
|
98
|
+
"#{(width / gcd).to_i}:#{(height / gcd).to_i}"
|
99
|
+
end
|
100
|
+
|
101
|
+
# Calculates width from aspect ratio and height:
|
102
|
+
# IE: 16:9 and 1080 returns -> 1920.
|
103
|
+
# @return int
|
104
|
+
def self.calc_width_from_ratio(ratio, height)
|
105
|
+
raise RuntimeError, "Unexpected ratio #{Blufin::Terminal::format_highlight(ratio)}, expected something like: 16:9" unless ratio =~ /\d{1,2}:\d{1,2}/
|
106
|
+
raise RuntimeError, "Expected integer, instead got: #{height}" unless height.to_s =~ /^\d+$/
|
107
|
+
rs = ratio.split(':')
|
108
|
+
((height.to_i / rs[1].to_i) * rs[0].to_i).to_i
|
109
|
+
end
|
110
|
+
|
111
|
+
# Calculates height from aspect ratio and width:
|
112
|
+
# IE: 16:9 and 1920 returns -> 1080.
|
113
|
+
# @return int
|
114
|
+
def self.calc_height_from_ratio(ratio, width)
|
115
|
+
raise RuntimeError, "Unexpected ratio #{Blufin::Terminal::format_highlight(ratio)}, expected something like: 16:9" unless ratio =~ /\d{1,2}:\d{1,2}/
|
116
|
+
raise RuntimeError, "Expected integer, instead got: #{width}" unless width.to_s =~ /^\d+$/
|
117
|
+
rs = ratio.split(':')
|
118
|
+
((width.to_i / rs[0].to_i) * rs[1].to_i).to_i
|
119
|
+
end
|
120
|
+
|
121
|
+
# Gets the greatest-common-denominator. Used to calculate screen aspect ratio.
|
122
|
+
# See: https://stackoverflow.com/questions/14731745/what-exactly-does-do-in-javascript
|
123
|
+
# @return int
|
124
|
+
def self.gcd(a, b)
|
125
|
+
a = a.to_i
|
126
|
+
b = b.to_i
|
127
|
+
return a if b == 0
|
128
|
+
gcd(b, a % b)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Standardizes the way output files are named.
|
132
|
+
# @return string
|
133
|
+
def self.calc_file_name(prefix, ext, side, length, ratio)
|
134
|
+
raise RuntimeError, "Expected integer, instead got: #{length}" unless length.to_s =~ /^\d+$/
|
135
|
+
raise RuntimeError, "Expected one of: #{VALID_SIDES.inspect}, instead got: #{side}" unless VALID_SIDES.include?(side)
|
136
|
+
raise RuntimeError, "Unexpected ratio #{Blufin::Terminal::format_highlight(ratio)}, expected something like: 16:9" unless ratio =~ /\d{1,2}:\d{1,2}/
|
137
|
+
x = side == 'width' ? length : calc_width_from_ratio(ratio, length)
|
138
|
+
y = side == 'width' ? calc_height_from_ratio(ratio, length) : length
|
139
|
+
"#{prefix}-#{x}x#{y}.#{ext.downcase}"
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
# Checks ImageMagick is installed on this system.
|
145
|
+
# @return void
|
146
|
+
def self.check_image_magick_installed
|
147
|
+
Blufin::Terminal::error('ImageMagick might not be installed.', "The command: #{Blufin::Terminal::format_command('magick')} was not found on this system.", true) unless system('magick -version >/dev/null')
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
@@ -7,17 +7,11 @@ module Blufin
|
|
7
7
|
# Checks if internet connection is present.
|
8
8
|
# @return boolean|void
|
9
9
|
def self.check_machine_is_online
|
10
|
-
|
11
10
|
begin
|
12
|
-
|
13
|
-
return true if open('http://www.google.com')
|
14
|
-
|
11
|
+
return true if open('https://www.google.com')
|
15
12
|
rescue
|
16
|
-
|
17
13
|
Blufin::Terminal::error('No internet connection', 'This script requires an internet connection and your machine is not online.')
|
18
|
-
|
19
14
|
end
|
20
|
-
|
21
15
|
end
|
22
16
|
|
23
17
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'highline/import'
|
2
2
|
require 'columnist'
|
3
3
|
require 'readline'
|
4
|
+
require 'tty-prompt'
|
4
5
|
require 'tty-spinner'
|
6
|
+
require 'rouge'
|
5
7
|
|
6
8
|
module Blufin
|
7
9
|
|
@@ -70,15 +72,43 @@ module Blufin
|
|
70
72
|
# Executes a command and shows that something is happening (via a cli-spinner)
|
71
73
|
# See: https://github.com/piotrmurach/tty-spinner/blob/master/lib/tty/spinner/formats.rb (for spinner options).
|
72
74
|
# @return void
|
73
|
-
def self.execute(command, path,
|
74
|
-
|
75
|
-
#
|
76
|
-
|
77
|
-
spinner = TTY::Spinner.new("[:spinner] \x1B[38;5;208m#{command} \x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;240m#{path}\x1B[0m", format: format)
|
75
|
+
def self.execute(command, path = nil, capture = false)
|
76
|
+
t1 = Time.now
|
77
|
+
spinner = TTY::Spinner.new("[:spinner] \x1B[38;5;208m#{command}#{!path.nil? ? " \x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;240m#{path}" : nil}\x1B[0m", format: :dots)
|
78
78
|
spinner.auto_spin
|
79
|
-
|
80
|
-
|
81
|
-
|
79
|
+
path = File.expand_path('~/') if path.nil?
|
80
|
+
if capture
|
81
|
+
res = system(`cd #{path} && #{command}`)
|
82
|
+
else
|
83
|
+
res = system("cd #{path} && #{command} > /tmp/execute-output")
|
84
|
+
end
|
85
|
+
t2 = Time.now
|
86
|
+
delta = "#{'%.3f' % (t2 - t1).abs}s"
|
87
|
+
if res || capture
|
88
|
+
spinner.success("\x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;46mComplete \x1B[38;5;240m(#{delta})\x1B[0m\x1B[0m")
|
89
|
+
else
|
90
|
+
spinner.error("\x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;196mFailed (#{delta})\x1B[0m")
|
91
|
+
puts "\x1B[38;5;240m"
|
92
|
+
system('cat /tmp/execute-output')
|
93
|
+
puts "\x1B[0m"
|
94
|
+
end
|
95
|
+
res
|
96
|
+
end
|
97
|
+
|
98
|
+
# Same as above but with a proc/lambda instead of a terminal command.
|
99
|
+
# @return void
|
100
|
+
def self.execute_proc(title, proc, verbose: true)
|
101
|
+
raise RuntimeError, "Expected String, instead got:#{title.class}" unless title.is_a?(String)
|
102
|
+
raise RuntimeError, "Expected proc to be an instance of Proc, instead got: #{proc.class}" unless proc.is_a?(Proc)
|
103
|
+
t1 = Time.now
|
104
|
+
spinner = nil
|
105
|
+
spinner = TTY::Spinner.new("[:spinner] \x1B[38;5;208m#{title}\x1B[0m", format: :dots) if verbose
|
106
|
+
spinner.auto_spin if verbose
|
107
|
+
res = proc.call
|
108
|
+
t2 = Time.now
|
109
|
+
delta = "#{'%.3f' % (t2 - t1).abs}s"
|
110
|
+
spinner.success("\x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;46mComplete \x1B[38;5;240m(#{delta})\x1B[0m\x1B[0m") if verbose && res
|
111
|
+
spinner.error("\x1B[38;5;246m\xe2\x86\x92 \x1B[38;5;196mFailed (#{delta})\x1B[0m") if verbose && !res
|
82
112
|
res
|
83
113
|
end
|
84
114
|
|
@@ -93,7 +123,7 @@ module Blufin
|
|
93
123
|
|
94
124
|
case type
|
95
125
|
when MSG_INFO
|
96
|
-
puts "\x1B[38;5;231m\x1B[48;5;
|
126
|
+
puts "\x1B[38;5;231m\x1B[48;5;22m Executing \x1B[0m \x1B[0m\xe2\x86\x92\x1B[0m \x1B[0m#{message}\x1B[0m\n"
|
97
127
|
when MSG_WARNING
|
98
128
|
puts "\x1B[38;5;231m\x1B[48;5;202m Warning \x1B[0m \x1B[0m\xe2\x86\x92\x1B[0m \x1B[0m#{message}\x1B[0m\n"
|
99
129
|
when MSG_ERROR
|
@@ -130,11 +160,9 @@ module Blufin
|
|
130
160
|
# @return void
|
131
161
|
def self.error(title = nil, message = nil, exit_script = true, preceding_blank_line = true, error_text = 'Error')
|
132
162
|
puts if preceding_blank_line
|
133
|
-
puts " \x1B[38;5;231m\x1B[48;5;
|
163
|
+
puts " \x1B[38;5;231m\x1B[48;5;124m #{error_text} \x1B[0m #{title.nil? ? '' : "\xe2\x86\x92 "}#{title}\n"
|
134
164
|
parse_messages(message)
|
135
|
-
if exit_script
|
136
|
-
exit
|
137
|
-
end
|
165
|
+
exit if exit_script
|
138
166
|
end
|
139
167
|
|
140
168
|
# Displays automatic message.
|
@@ -157,7 +185,7 @@ module Blufin
|
|
157
185
|
# @return void
|
158
186
|
def self.success(title = nil, message = nil, preceding_blank_line = true)
|
159
187
|
puts if preceding_blank_line
|
160
|
-
puts " \x1B[38;5;231m\x1B[48;5;
|
188
|
+
puts " \x1B[38;5;231m\x1B[48;5;22m Success \x1B[0m #{title.nil? ? '' : "\xe2\x86\x92 "}#{title}\n"
|
161
189
|
parse_messages(message)
|
162
190
|
end
|
163
191
|
|
@@ -169,6 +197,16 @@ module Blufin
|
|
169
197
|
parse_messages(message)
|
170
198
|
end
|
171
199
|
|
200
|
+
# Displays warning message.
|
201
|
+
# @return void
|
202
|
+
def self.arg_instructions(arg_descriptions, preceding_blank_line = true)
|
203
|
+
puts if preceding_blank_line
|
204
|
+
puts " \x1B[38;5;231m\x1B[48;5;22m Instructions \x1B[0m \xe2\x86\x92 This command expects the following arguments:\n"
|
205
|
+
arg_descriptions_converted = []
|
206
|
+
arg_descriptions.each_with_index { |x, idx| arg_descriptions_converted << "#{idx + 1}) \x1B[38;5;208m#{x}\x1B[0m" }
|
207
|
+
parse_messages(arg_descriptions_converted)
|
208
|
+
end
|
209
|
+
|
172
210
|
# Displays custom message (ideally, keyword should be 7 characters long to match the rest of the output).
|
173
211
|
# @return void
|
174
212
|
def self.custom(keyword = 'N/A', color = 1, title = nil, message = nil, preceding_blank_line = true)
|
@@ -179,6 +217,7 @@ module Blufin
|
|
179
217
|
|
180
218
|
# Displays custom message with a progress indicator.
|
181
219
|
# @return void
|
220
|
+
# Deprecated
|
182
221
|
def self.custom_progress(keyword = 'N/A', color = 1, title = nil, message = nil, preceding_blank_line = true)
|
183
222
|
puts if preceding_blank_line
|
184
223
|
puts " \x1B[38;5;231m\x1B[48;5;#{color}m #{keyword} \x1B[0m #{title.nil? ? '' : "\xe2\x86\x92 "}#{title}\n"
|
@@ -189,7 +228,7 @@ module Blufin
|
|
189
228
|
# @return String
|
190
229
|
def self.format_action(action_text, capitalize = true)
|
191
230
|
action_text = action_text.nil? ? 'N/A' : action_text
|
192
|
-
action_text = action_text.upcase if capitalize
|
231
|
+
action_text = action_text.to_s.upcase if capitalize
|
193
232
|
"\x1B[38;5;170m#{action_text}\x1B[0m"
|
194
233
|
end
|
195
234
|
|
@@ -215,13 +254,12 @@ module Blufin
|
|
215
254
|
# Returns flag name in consistent, uniform manner.
|
216
255
|
# @return String
|
217
256
|
def self.format_flag(flag_letter, display_flag_text = true)
|
218
|
-
letter_array = []
|
219
257
|
if flag_letter.is_a? String
|
220
|
-
letter_array =
|
258
|
+
letter_array = [flag_letter]
|
221
259
|
elsif flag_letter.is_a? Array
|
222
260
|
letter_array = flag_letter
|
223
261
|
else
|
224
|
-
|
262
|
+
raise RuntimeError, 'Terminal::format_flag expects either String or Array.'
|
225
263
|
end
|
226
264
|
flag_txt = ''
|
227
265
|
letter_array.each do |letter|
|
@@ -229,7 +267,7 @@ module Blufin
|
|
229
267
|
end
|
230
268
|
xtra_txt = letter_array.length > 1 ? ' flags' : ' flag'
|
231
269
|
flag_txt = flag_txt[2..-1]
|
232
|
-
"\x1B[38;5;
|
270
|
+
"\x1B[38;5;177m#{flag_txt}#{display_flag_text ? xtra_txt : ''}\x1B[0m"
|
233
271
|
end
|
234
272
|
|
235
273
|
# Returns action message in consistent, uniform manner.
|
@@ -286,39 +324,162 @@ module Blufin
|
|
286
324
|
when 'x'
|
287
325
|
Blufin::Terminal::error('Abandon ship!', ["You have chosen to \x1B[38;5;9mABORT\x1B[38;5;240m the script.", nil, 'Please note that whenever you do this, any scripted tasks which were running', 'will have been interrupted mid-script. This may (or may not) cause problems.'], true)
|
288
326
|
else
|
327
|
+
raise RuntimeError, "Un-handled response: #{response.downcase}"
|
289
328
|
end
|
290
329
|
end
|
291
330
|
|
292
331
|
# Shows a prompt waiting for user input.
|
293
332
|
# If validation_proc is passed, the Proc must return TRUE in order for validation to pass.
|
294
333
|
# @return string
|
295
|
-
|
334
|
+
# @deprecated
|
335
|
+
def self.prompt_for_input(title = 'Input Required', message = nil, subtitle_array = nil, validation_proc = nil, validation_message = 'Invalid value', clear_screen = true, preceding_blank_line = true)
|
296
336
|
system('clear') if clear_screen
|
297
337
|
puts if preceding_blank_line
|
298
|
-
puts " \x1B[38;5;231m\x1B[48;5;125m
|
338
|
+
puts " \x1B[38;5;231m\x1B[48;5;125m #{title.upcase} \x1B[0m \xe2\x86\x92 #{message} \x1B[38;5;240m\xe2\x80\x94 \x1B[38;5;160m(or 'X' to cancel)\x1B[0m\n"
|
299
339
|
parse_messages(subtitle_array) unless subtitle_array.nil?
|
300
340
|
puts if subtitle_array.nil?
|
301
341
|
response = nil
|
302
342
|
while response.nil?
|
303
343
|
response = Readline::readline(" \x1B[38;5;245m=>\x1B[0m ", true)
|
304
|
-
unless nil_allowed
|
305
|
-
response.strip!
|
306
|
-
response = nil if response == '' || response.nil?
|
307
|
-
end
|
308
344
|
unless validation_proc.nil?
|
309
345
|
raise RuntimeError, "Expected validation_proc to be an instance of Proc, instead got: #{validation_proc.class}" unless validation_proc.is_a?(Proc)
|
310
|
-
unless validation_proc.call(response)
|
346
|
+
unless response.upcase == 'X' || validation_proc.call(response)
|
311
347
|
puts " \x1B[38;5;245m=>\x1B[0m \x1B[38;5;196mERROR\x1B[0m \xe2\x80\x94 #{validation_message}\n"
|
312
348
|
response = nil
|
313
349
|
end
|
314
350
|
end
|
315
351
|
end
|
352
|
+
abort if response.upcase == 'X'
|
316
353
|
puts
|
317
354
|
response
|
318
355
|
end
|
319
356
|
|
357
|
+
# See: https://github.com/piotrmurach/tty-prompt#1-usage
|
358
|
+
# See: https://www.rubydoc.info/gems/tty-prompt
|
359
|
+
# => What is your name? (Albert Rannetsperger)
|
360
|
+
# @return string
|
361
|
+
def self.prompt_ask(question, default: nil, help: nil, validation_regex: nil)
|
362
|
+
puts display_prompt_help(help) unless help.nil?
|
363
|
+
prompt = TTY::Prompt.new
|
364
|
+
prompt.ask(display_prompt_text(question), default: default) do |q|
|
365
|
+
q.modify :strip
|
366
|
+
q.validate validation_regex unless validation_regex.nil?
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
# => Do you like Ruby? (Y/n)
|
371
|
+
# @return boolean
|
372
|
+
def self.prompt_yes?(question)
|
373
|
+
begin
|
374
|
+
prompt = TTY::Prompt.new
|
375
|
+
return prompt.yes?(display_prompt_text(question))
|
376
|
+
rescue
|
377
|
+
prompt_yes?(question)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
# => What is your secret? ••••
|
382
|
+
# @return string
|
383
|
+
def self.prompt_mask(question)
|
384
|
+
prompt = TTY::Prompt.new
|
385
|
+
prompt.mask(display_prompt_text(question))
|
386
|
+
end
|
387
|
+
|
388
|
+
# Choose your destiny? (Use ↑/↓ arrow keys, press Enter to select)
|
389
|
+
# ‣ Scorpion
|
390
|
+
# Kano
|
391
|
+
# Jax
|
392
|
+
# @options = %w(Scorpion Kano Jax)
|
393
|
+
# @options = [{ :text => 'Description', :value => '1', :disabled => nil/'Reason' }]
|
394
|
+
# @return string
|
395
|
+
def self.prompt_select(question, options, help: nil, per_page: 20)
|
396
|
+
raise RuntimeError, "Expected Array, instead got #{options.class}" unless options.is_a?(Array)
|
397
|
+
raise RuntimeError, 'Array cannot be empty.' unless options.any?
|
398
|
+
puts display_prompt_help(help) unless help.nil?
|
399
|
+
prompt = TTY::Prompt.new
|
400
|
+
if options[0].is_a?(String)
|
401
|
+
prompt.select(display_prompt_text(question), options, per_page: per_page)
|
402
|
+
elsif options[0].is_a?(Hash)
|
403
|
+
prompt.select(display_prompt_text(question), per_page: per_page) do |menu|
|
404
|
+
options.each do |option|
|
405
|
+
raise RuntimeError, "Expected option to be Hash, instead got: (#{option.class}) #{option.inspect}" unless option.is_a?(Hash)
|
406
|
+
raise RuntimeError, 'Option is missing key => :text' unless option.has_key?(:text)
|
407
|
+
raise RuntimeError, 'Option is missing key => :value' unless option.has_key?(:value)
|
408
|
+
raise RuntimeError, "Expected :disabled option to be String, instead got: #{option[:disabled].class}" if option.has_key?(:disabled) && !option[:disabled].is_a?(String) && !option[:disabled].nil?
|
409
|
+
menu.choice option[:text], option[:value] unless option.has_key?(:disabled)
|
410
|
+
menu.choice option[:text], option[:value], disabled: "\x1B[38;5;196m#{option[:disabled]}\x1B[0m" if option.has_key?(:disabled)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
else
|
414
|
+
raise RuntimeError, "Expected options Array to consist of either Strings or Hashes, instead got: #{options.inspect}"
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
# Select drinks? (Use ↑/↓ arrow keys, press Space to select and Enter to finish)"
|
419
|
+
# ‣ ⬡ vodka
|
420
|
+
# ⬡ beer
|
421
|
+
# ⬡ wine
|
422
|
+
# ⬡ whisky
|
423
|
+
# ⬡ bourbon
|
424
|
+
# @options = %w(vodka beer wine whisky bourbon)
|
425
|
+
# @return Array
|
426
|
+
def self.prompt_multi_select(question, options)
|
427
|
+
raise RuntimeError, "Expected Array, instead got #{options.class}" unless options.is_a?(Array)
|
428
|
+
prompt = TTY::Prompt.new
|
429
|
+
prompt.multi_select(display_prompt_text(question), options)
|
430
|
+
end
|
431
|
+
|
432
|
+
# Select an editor?
|
433
|
+
# 1) emacs
|
434
|
+
# 2) nano
|
435
|
+
# 3) vim
|
436
|
+
# Choose 1-3 [1]:
|
437
|
+
# @options = %w(emacs nano vim)
|
438
|
+
# @return Array
|
439
|
+
def self.prompt_enum_select(question, options)
|
440
|
+
raise RuntimeError, "Expected Array, instead got #{options.class}" unless options.is_a?(Array)
|
441
|
+
prompt = TTY::Prompt.new
|
442
|
+
prompt.enum_select(display_prompt_text(question), options)
|
443
|
+
end
|
444
|
+
|
445
|
+
# Overwrite Gemfile? (enter "h" for help) [y,n,a,d,q,h]
|
446
|
+
# @options = [
|
447
|
+
# { key: 'y', name: 'overwrite this file', value: :yes },
|
448
|
+
# { key: 'n', name: 'do not overwrite this file', value: :no },
|
449
|
+
# { key: 'a', name: 'overwrite this file and all later files', value: :all },
|
450
|
+
# { key: 'd', name: 'show diff', value: :diff },
|
451
|
+
# { key: 'q', name: 'quit; do not overwrite this file ', value: :quit }
|
452
|
+
# ]
|
453
|
+
# @return multiple
|
454
|
+
def self.prompt_expand(question, options)
|
455
|
+
raise RuntimeError, "Expected Array, instead got #{options.class}" unless options.is_a?(Array)
|
456
|
+
options.each do |option|
|
457
|
+
found_key = false
|
458
|
+
found_name = false
|
459
|
+
found_value = false
|
460
|
+
option.each do |k, v|
|
461
|
+
case k
|
462
|
+
when :key
|
463
|
+
found_key = true
|
464
|
+
when :name
|
465
|
+
found_name = true
|
466
|
+
when :value
|
467
|
+
found_value = true
|
468
|
+
else
|
469
|
+
raise RuntimeError, "Unrecognized Key: #{k}"
|
470
|
+
end
|
471
|
+
end
|
472
|
+
raise RuntimeError, "Option is missing #{Blufin::Terminal::format_highlight('key')}: #{option.inspect}" unless found_key
|
473
|
+
raise RuntimeError, "Option is missing #{Blufin::Terminal::format_highlight('name')}: #{option.inspect}" unless found_name
|
474
|
+
raise RuntimeError, "Option is missing #{Blufin::Terminal::format_highlight('value')}: #{option.inspect}" unless found_value
|
475
|
+
end
|
476
|
+
prompt = TTY::Prompt.new
|
477
|
+
prompt.expand(display_prompt_text(question), options)
|
478
|
+
end
|
479
|
+
|
320
480
|
# Gives a prompt where ANY KEY will continue executing the script.
|
321
481
|
# @return void
|
482
|
+
# @deprecated
|
322
483
|
def self.any_key_to_continue(text = nil, preceding_blank_line = true)
|
323
484
|
STDOUT.flush
|
324
485
|
puts if preceding_blank_line
|
@@ -383,6 +544,30 @@ module Blufin
|
|
383
544
|
Blufin::Terminal::automatic(message, file_output, preceding_blank_line)
|
384
545
|
end
|
385
546
|
|
547
|
+
# Outputs code to terminal that is syntax highlighted.
|
548
|
+
# @return void
|
549
|
+
def self.code_highlight_file(path_and_file, type, indent = 5)
|
550
|
+
raise RuntimeError, "File does not exist: #{path_and_file}" unless Blufin::Files::file_exists(path_and_file)
|
551
|
+
code_highlight(File.read(path_and_file), type, indent)
|
552
|
+
end
|
553
|
+
|
554
|
+
# Outputs code to terminal that is syntax highlighted.
|
555
|
+
# @return void
|
556
|
+
def self.code_highlight(string, type, indent = 5)
|
557
|
+
raise RuntimeError, "Expected String, instead got:#{string.class}" unless string.is_a?(String)
|
558
|
+
type = type.downcase
|
559
|
+
types = {
|
560
|
+
'yml' => Rouge::Lexers::YAML.new,
|
561
|
+
'json' => Rouge::Lexers::JSON.new
|
562
|
+
}
|
563
|
+
raise RuntimeError, "Lexer not defined for type: #{type}" unless types.has_key?(type)
|
564
|
+
repeat = ' ' * indent
|
565
|
+
formatter = Rouge::Formatters::Terminal256.new
|
566
|
+
formatter.format(types[type].lex(string)).split("\n").each do |line|
|
567
|
+
puts "#{repeat}#{line}"
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
386
571
|
private
|
387
572
|
|
388
573
|
# Parses messages for various output functions.
|
@@ -408,6 +593,17 @@ module Blufin
|
|
408
593
|
end
|
409
594
|
end
|
410
595
|
|
411
|
-
|
596
|
+
# Standardized way of displaying prompts help.
|
597
|
+
# @return string
|
598
|
+
def self.display_prompt_help(help)
|
599
|
+
"\x1B[38;5;240m#{help}\x1B[0m"
|
600
|
+
end
|
412
601
|
|
602
|
+
# Standardized way of displaying prompts text.
|
603
|
+
# @return string
|
604
|
+
def self.display_prompt_text(question)
|
605
|
+
"\x1B[38;5;208m#{question}\x1B[38;5;240m =>\x1B[0m"
|
606
|
+
end
|
607
|
+
|
608
|
+
end
|
413
609
|
end
|
File without changes
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Blufin
|
2
|
+
|
3
|
+
class Validate
|
4
|
+
|
5
|
+
# Passing arguments as follows...
|
6
|
+
# @expected: { 'required_key' => true, 'optional_key' => false }
|
7
|
+
# @actual: %w(required_key non_existent_key)
|
8
|
+
# @description: Hint of where the error occurred.
|
9
|
+
# @return null - If errors, will raise exception.
|
10
|
+
def self.assert_valid_keys(expected, actual, description)
|
11
|
+
raise RuntimeError, "Expected Hash, instead got: #{expected.class}" unless expected.is_a?(Hash)
|
12
|
+
raise RuntimeError, "Expected Array, instead got: #{actual.class}" unless actual.is_a?(Array)
|
13
|
+
errors = []
|
14
|
+
required_keys = []
|
15
|
+
optional_keys = []
|
16
|
+
expected.each do |k, v|
|
17
|
+
raise RuntimeError, "Expected value for #{k} to be boolean, instead got: #{v.class}" unless !!v == v
|
18
|
+
required_keys << k if v
|
19
|
+
optional_keys << k unless v
|
20
|
+
end
|
21
|
+
actual.each do |n|
|
22
|
+
errors << "Unexpected Key: #{n}" unless required_keys.include?(n) || optional_keys.include?(n)
|
23
|
+
required_keys.delete(n) if required_keys.include?(n)
|
24
|
+
optional_keys.delete(n) if optional_keys.include?(n)
|
25
|
+
end
|
26
|
+
errors << "Missing required keys: #{required_keys.inspect}" unless required_keys.length == 0
|
27
|
+
if errors.length == 0
|
28
|
+
expected_key_order = []
|
29
|
+
expected.each do |k, v|
|
30
|
+
expected_key_order << k if v
|
31
|
+
expected_key_order << k if !v && actual.include?(k)
|
32
|
+
end
|
33
|
+
unless expected_key_order.to_s == actual.to_s
|
34
|
+
errors << "Expected key order doesn't match:"
|
35
|
+
errors << ''
|
36
|
+
errors << " Expected: #{expected_key_order.inspect}"
|
37
|
+
errors << " Actual: #{actual.inspect}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
return unless errors.length > 0
|
41
|
+
# Output useful errors (hopefully).
|
42
|
+
puts
|
43
|
+
puts Blufin::Terminal::format_invalid(description)
|
44
|
+
puts expected.to_yaml
|
45
|
+
puts
|
46
|
+
errors.each { |error| puts "\x1B[38;5;196m #{error}\x1B[0m" }
|
47
|
+
raise RuntimeError, 'Keys are invalid, missing and/or not in the expected order.'
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
data/lib/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
BLUFIN_LIB_VERSION = '1.
|
1
|
+
BLUFIN_LIB_VERSION = '1.5.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blufin-lib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Albert Rannetsperger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -38,20 +38,34 @@ dependencies:
|
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 2.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tty-prompt
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.19.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.19.0
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: tty-spinner
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - '='
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.9.
|
61
|
+
version: 0.9.1
|
48
62
|
type: :runtime
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - '='
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.9.
|
68
|
+
version: 0.9.1
|
55
69
|
description: Common functionality shared between ruby gems.
|
56
70
|
email: alb3rtuk@hotmail.com
|
57
71
|
executables: []
|
@@ -59,19 +73,20 @@ extensions: []
|
|
59
73
|
extra_rdoc_files: []
|
60
74
|
files:
|
61
75
|
- lib/blufin-lib.rb
|
62
|
-
- lib/
|
63
|
-
- lib/
|
64
|
-
- lib/
|
65
|
-
- lib/
|
66
|
-
- lib/
|
67
|
-
- lib/
|
68
|
-
- lib/
|
69
|
-
- lib/
|
70
|
-
- lib/
|
71
|
-
- lib/
|
72
|
-
- lib/
|
73
|
-
- lib/
|
74
|
-
- lib/
|
76
|
+
- lib/core/arrays.rb
|
77
|
+
- lib/core/browser.rb
|
78
|
+
- lib/core/datetime_utils.rb
|
79
|
+
- lib/core/encryptor.rb
|
80
|
+
- lib/core/files.rb
|
81
|
+
- lib/core/image.rb
|
82
|
+
- lib/core/network.rb
|
83
|
+
- lib/core/numbers.rb
|
84
|
+
- lib/core/routes.rb
|
85
|
+
- lib/core/ssh.rb
|
86
|
+
- lib/core/strings.rb
|
87
|
+
- lib/core/terminal.rb
|
88
|
+
- lib/core/tools.rb
|
89
|
+
- lib/core/validate.rb
|
75
90
|
- lib/version.rb
|
76
91
|
homepage: https://github.com/alb3rtuk
|
77
92
|
licenses:
|
@@ -1,98 +0,0 @@
|
|
1
|
-
module Blufin
|
2
|
-
|
3
|
-
module Test
|
4
|
-
|
5
|
-
class EnvironmentValidator
|
6
|
-
|
7
|
-
CHECK_API = 'check-api'
|
8
|
-
CHECK_CRON = 'check-cron'
|
9
|
-
CHECK_WORKER = 'check-worker'
|
10
|
-
CHECK_MYSQL = 'check-mysql'
|
11
|
-
CHECK_RABBIT_MQ = 'check-rabbit-mq'
|
12
|
-
|
13
|
-
def initialize(opts, base_prefix)
|
14
|
-
|
15
|
-
raise RuntimeError, "Opts must be an array, you passed: #{opts.class}" unless opts.is_a?(Hash)
|
16
|
-
|
17
|
-
@base_prefix = base_prefix
|
18
|
-
|
19
|
-
valid_opts = [CHECK_API, CHECK_CRON, CHECK_WORKER, CHECK_MYSQL, CHECK_RABBIT_MQ]
|
20
|
-
|
21
|
-
opts.keys.each { |opt| raise RuntimeError, "#{opt} is not a valid value" unless valid_opts.include?(opt) }
|
22
|
-
|
23
|
-
Blufin::Terminal::info('Checking for necessary components...') if opts.length > 0
|
24
|
-
|
25
|
-
validation_results = []
|
26
|
-
validation_results << check_api(opts[CHECK_API]) if opts.keys.include?(CHECK_API)
|
27
|
-
validation_results << check_cron(opts[CHECK_CRON]) if opts.keys.include?(CHECK_CRON)
|
28
|
-
validation_results << check_worker(opts[CHECK_WORKER]) if opts.keys.include?(CHECK_WORKER)
|
29
|
-
validation_results << check_mysql if opts.keys.include?(CHECK_MYSQL)
|
30
|
-
validation_results << check_rabbit_mq if opts.keys.include?(CHECK_RABBIT_MQ)
|
31
|
-
|
32
|
-
Blufin::Terminal::error('Your environment is not setup correctly. Please check the above output.', nil, true) if validation_results.include?(false)
|
33
|
-
|
34
|
-
puts
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
# Checks that the API is running.
|
41
|
-
# @return void
|
42
|
-
def check_api(uri)
|
43
|
-
check_service_common(uri, 'api')
|
44
|
-
end
|
45
|
-
|
46
|
-
# Checks that the WORKER is running.
|
47
|
-
# @return void
|
48
|
-
def check_cron(uri)
|
49
|
-
check_service_common(uri, 'cron')
|
50
|
-
end
|
51
|
-
|
52
|
-
# Checks that the WORKER is running.
|
53
|
-
# @return void
|
54
|
-
def check_worker(uri)
|
55
|
-
check_service_common(uri, 'worker')
|
56
|
-
end
|
57
|
-
|
58
|
-
# Checks that the MySQL is running.
|
59
|
-
# @return void
|
60
|
-
def check_mysql
|
61
|
-
if system('mysqladmin version >& /dev/null')
|
62
|
-
Blufin::Terminal::output(Blufin::Terminal::format_highlight('mysql'), Blufin::Terminal::MSG_CUSTOM_AUTO_PAD, 'Pass', 22)
|
63
|
-
true
|
64
|
-
else
|
65
|
-
Blufin::Terminal::output(Blufin::Terminal::format_invalid('mysql'), Blufin::Terminal::MSG_CUSTOM_AUTO_PAD, 'Fail', 196)
|
66
|
-
false
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Checks that the RabbitMQ is running.
|
71
|
-
# @return void
|
72
|
-
def check_rabbit_mq
|
73
|
-
if system('rabbitmqadmin --help >& /dev/null')
|
74
|
-
Blufin::Terminal::output(Blufin::Terminal::format_highlight('rabbit-mq'), Blufin::Terminal::MSG_CUSTOM_AUTO_PAD, 'Pass', 22)
|
75
|
-
return true
|
76
|
-
else
|
77
|
-
Blufin::Terminal::output(Blufin::Terminal::format_invalid('rabbit-mq'), Blufin::Terminal::MSG_CUSTOM_AUTO_PAD, 'Fail', 196)
|
78
|
-
end
|
79
|
-
false
|
80
|
-
end
|
81
|
-
|
82
|
-
# Common method for checking Java services are running.
|
83
|
-
def check_service_common(uri, service_name)
|
84
|
-
service_name = "#{@base_prefix}-#{service_name}"
|
85
|
-
if system("curl -I #{uri} -k >& /dev/null")
|
86
|
-
Blufin::Terminal::output(Blufin::Terminal::format_highlight(service_name), Blufin::Terminal::MSG_CUSTOM_AUTO_PAD, 'Pass', 22)
|
87
|
-
return true
|
88
|
-
else
|
89
|
-
Blufin::Terminal::output(Blufin::Terminal::format_invalid(service_name), Blufin::Terminal::MSG_CUSTOM_AUTO_PAD, 'Fail', 196)
|
90
|
-
end
|
91
|
-
false
|
92
|
-
end
|
93
|
-
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|