blufin-lib 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|