sct 0.1.14 → 0.1.19
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/bin/sct +3 -4
- data/{.DS_Store → cluster/lib/.DS_Store} +0 -0
- data/cluster/lib/cluster.rb +6 -0
- data/cluster/lib/cluster/commands_generator.rb +95 -0
- data/cluster/lib/cluster/module.rb +7 -0
- data/cluster/lib/cluster/runner.rb +239 -0
- data/{lib → sct/lib}/.DS_Store +0 -0
- data/sct/lib/sct.rb +17 -0
- data/sct/lib/sct/.DS_Store +0 -0
- data/sct/lib/sct/cli_tools_distributor.rb +46 -0
- data/{lib → sct/lib}/sct/command.rb +0 -0
- data/sct/lib/sct/commands/hostfile.rb +68 -0
- data/sct/lib/sct/commands/init.rb +37 -0
- data/sct/lib/sct/commands/mysqlproxy.rb +20 -0
- data/sct/lib/sct/commands_generator.rb +56 -0
- data/sct/lib/sct/tools.rb +12 -0
- data/sct/lib/sct/version.rb +3 -0
- data/sct_core/lib/.DS_Store +0 -0
- data/sct_core/lib/sct_core.rb +13 -0
- data/{lib/sct → sct_core/lib/sct_core}/.DS_Store +0 -0
- data/sct_core/lib/sct_core/command_executor.rb +104 -0
- data/{lib/sct → sct_core/lib/sct_core}/config.rb +3 -3
- data/sct_core/lib/sct_core/core_ext/string.rb +9 -0
- data/{lib/sct/setup/helpers.rb → sct_core/lib/sct_core/helper.rb} +2 -2
- data/sct_core/lib/sct_core/module.rb +0 -0
- data/sct_core/lib/sct_core/sct_pty.rb +53 -0
- data/sct_core/lib/sct_core/ui/implementations/shell.rb +129 -0
- data/sct_core/lib/sct_core/ui/interface.rb +120 -0
- data/sct_core/lib/sct_core/ui/ui.rb +26 -0
- data/shell/README.md +0 -0
- data/shell/lib/shell.rb +3 -0
- data/{lib/sct → shell/lib/shell}/ClassLevelInheritableAttributes.rb +0 -0
- data/shell/lib/shell/commands_generator.rb +14 -0
- data/{lib/sct → shell/lib/shell}/docker/composer.rb +4 -3
- data/{lib/sct → shell/lib/shell}/docker/docker.rb +7 -10
- data/{lib/sct → shell/lib/shell}/docker/php.rb +3 -2
- data/{lib/sct → shell/lib/shell}/docker/yarn.rb +4 -3
- data/shell/lib/shell/module.rb +9 -0
- data/shell/lib/shell/runner.rb +34 -0
- data/shell/lib/shell/tools.rb +7 -0
- metadata +92 -54
- data/.gitignore +0 -12
- data/.rspec +0 -3
- data/.travis.yml +0 -7
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -48
- data/LICENSE.txt +0 -21
- data/README.md +0 -134
- data/Rakefile +0 -6
- data/lib/sct.rb +0 -61
- data/lib/sct/command_interface.rb +0 -18
- data/lib/sct/command_option.rb +0 -14
- data/lib/sct/commands/cluster.rb +0 -121
- data/lib/sct/commands/composer.rb +0 -29
- data/lib/sct/commands/hostfile.rb +0 -125
- data/lib/sct/commands/init.rb +0 -51
- data/lib/sct/commands/mysqlproxy.rb +0 -38
- data/lib/sct/commands/php.rb +0 -37
- data/lib/sct/commands/yarn.rb +0 -26
- data/lib/sct/version.rb +0 -3
- data/sct.gemspec +0 -40
File without changes
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Sct
|
2
|
+
class HostfileCommand
|
3
|
+
|
4
|
+
def execute(args, options)
|
5
|
+
return UI.error("SCT has not been initialized. Run 'sct init' first.") unless SctCore::Config.exists
|
6
|
+
|
7
|
+
return UI.error("This command needs to be run with sudo.") unless SctCore::Helper.isSudo
|
8
|
+
|
9
|
+
return unless SctCore::Helper.ingressAddress
|
10
|
+
|
11
|
+
ingressAddress = SctCore::Helper.ingressAddress
|
12
|
+
|
13
|
+
entries = [
|
14
|
+
{
|
15
|
+
host: "spend.cloud.local",
|
16
|
+
comment: "The spend cloud ingress url"
|
17
|
+
},
|
18
|
+
{
|
19
|
+
host: "mail.spend.cloud.local",
|
20
|
+
comment: "The spend cloud mail url"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
host: "config.spend.cloud.local",
|
24
|
+
comment: "The spend cloud config url"
|
25
|
+
},
|
26
|
+
{
|
27
|
+
host: "spend-cloud.spend.cloud.local",
|
28
|
+
comment: "The spend cloud web app url"
|
29
|
+
},
|
30
|
+
{
|
31
|
+
host: "docs.spend.cloud.local",
|
32
|
+
comment: "The spend cloud documentation url"
|
33
|
+
}
|
34
|
+
]
|
35
|
+
|
36
|
+
if options.path
|
37
|
+
hosts_paths = [options.path]
|
38
|
+
else
|
39
|
+
hosts_paths = ["/etc/hosts"]
|
40
|
+
|
41
|
+
if SctCore::Helper.operatingSystem == SctCore::Helper::WINDOWS
|
42
|
+
hosts_paths << "/mnt/c/Windows/System32/drivers/etc/hosts"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
hosts_paths.each do |hosts_path|
|
47
|
+
line_ending = hosts_path == "/mnt/c/Windows/System32/drivers/etc/hosts" ? "\r\n" : "\n"
|
48
|
+
|
49
|
+
lines = File.readlines hosts_path
|
50
|
+
|
51
|
+
# select the lines that do not include any entry
|
52
|
+
lines = lines.select { |line| ! entries.any? { |entry| line.include? entry[:host] } }
|
53
|
+
|
54
|
+
# add entries
|
55
|
+
entries.each do |entry|
|
56
|
+
lines << "#{ingressAddress} #{entry[:host]} # #{entry[:comment]}#{line_ending}"
|
57
|
+
end
|
58
|
+
|
59
|
+
File.write hosts_path, lines.join
|
60
|
+
|
61
|
+
UI.success("Patched #{hosts_path} with #{ingressAddress}")
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'sct_core/ui/ui'
|
2
|
+
require 'sct_core/config'
|
3
|
+
|
4
|
+
module Sct
|
5
|
+
|
6
|
+
class InitCommand
|
7
|
+
|
8
|
+
def execute(args, options)
|
9
|
+
|
10
|
+
dir = SctCore::Config.dir
|
11
|
+
|
12
|
+
cli = HighLine.new
|
13
|
+
|
14
|
+
email = cli.ask("What is your email address?") { |q|
|
15
|
+
q.validate = URI::MailTo::EMAIL_REGEXP
|
16
|
+
}
|
17
|
+
|
18
|
+
cloud_proxy_path = cli.ask("What is the path of your cloud proxy json credentials?") { |q|
|
19
|
+
q.default = "~/.config/gcloud/application_default_credentials.json"
|
20
|
+
}
|
21
|
+
|
22
|
+
contents = ""
|
23
|
+
contents << "email=#{email}\n"
|
24
|
+
contents << "cloud-proxy-path=#{File.expand_path(cloud_proxy_path)}\n"
|
25
|
+
|
26
|
+
if !File.directory?(dir)
|
27
|
+
FileUtils.mkdir_p(dir)
|
28
|
+
end
|
29
|
+
|
30
|
+
File.write(SctCore::Config.path, contents)
|
31
|
+
|
32
|
+
puts "Generated config file at #{SctCore::Config.path}"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Sct
|
2
|
+
class MysqlproxyCommand
|
3
|
+
|
4
|
+
DEFAULT_SECRET_NAME = "gcloud-credentials"
|
5
|
+
|
6
|
+
def execute(args, options)
|
7
|
+
|
8
|
+
return UI.error("SCT has not been initialized. Run 'sct init' first.") unless SctCore::Config.exists
|
9
|
+
|
10
|
+
path = SctCore::Config.get('cloud-proxy-path')
|
11
|
+
|
12
|
+
system("kubectl delete secret gcloud-credentials")
|
13
|
+
system("kubectl create secret generic gcloud-credentials --from-file=#{path}")
|
14
|
+
|
15
|
+
UI.success("Authenticated with secret-name: '#{DEFAULT_SECRET_NAME}'")
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'commander'
|
2
|
+
require 'sct/command'
|
3
|
+
|
4
|
+
module Sct
|
5
|
+
class CommandsGenerator
|
6
|
+
include Commander::Methods
|
7
|
+
|
8
|
+
def self.start
|
9
|
+
self.new.run
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
program :name, 'sct'
|
14
|
+
program :version, Sct::VERSION
|
15
|
+
program :summary, 'CLI helper tool for local SCT development'
|
16
|
+
program :description, 'SCT is a CLI tool for developers using the Visma Continuous Deployment Model in conjunction with the Google Cloud Platform (GCP). It provides multiple command to set up and maintain a kubernetes cluster on a machine for local development'
|
17
|
+
|
18
|
+
global_option('--verbose') { $verbose = true }
|
19
|
+
|
20
|
+
command :init do |c|
|
21
|
+
c.syntax = 'sct init'
|
22
|
+
c.description = 'setup sct'
|
23
|
+
|
24
|
+
c.action do |args, options|
|
25
|
+
UI.important("setting up sct")
|
26
|
+
Sct::InitCommand.new.execute(args, options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
command :hostfile do |c|
|
31
|
+
|
32
|
+
c.syntax = 'sct hostfile'
|
33
|
+
c.description = 'patch hostfile with kubernetes ip'
|
34
|
+
|
35
|
+
c.action do |args, options|
|
36
|
+
UI.important("Trying to patch hostfile")
|
37
|
+
Sct::HostfileCommand.new.execute(args, options)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
command :'mysql proxy' do |c|
|
42
|
+
|
43
|
+
c.syntax = 'sct mysql proxy'
|
44
|
+
c.description = 'setup google mysql proxy'
|
45
|
+
|
46
|
+
c.action do |args, options|
|
47
|
+
UI.important("Trying to setup mysql proxy")
|
48
|
+
Sct::MysqlproxyCommand.new.execute(args, options)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
run!
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
Binary file
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'sct_core/core_ext/string'
|
2
|
+
require_relative 'sct_core/config'
|
3
|
+
require_relative 'sct_core/helper'
|
4
|
+
require_relative 'sct_core/command_executor'
|
5
|
+
require_relative 'sct_core/ui/ui'
|
6
|
+
require_relative 'sct_core/sct_pty'
|
7
|
+
|
8
|
+
# third party code
|
9
|
+
require 'colored'
|
10
|
+
require 'commander'
|
11
|
+
|
12
|
+
# these need to be imported after commander
|
13
|
+
require_relative 'sct_core/module'
|
Binary file
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require_relative 'ui/ui'
|
2
|
+
require_relative 'sct_pty'
|
3
|
+
|
4
|
+
module SctCore
|
5
|
+
# Executes commands and takes care of error handling and more
|
6
|
+
class CommandExecutor
|
7
|
+
class << self
|
8
|
+
# Cross-platform way of finding an executable in the $PATH. Respects the $PATHEXT, which lists
|
9
|
+
# valid file extensions for executables on Windows.
|
10
|
+
#
|
11
|
+
# which('ruby') #=> /usr/bin/ruby
|
12
|
+
#
|
13
|
+
# Derived from https://stackoverflow.com/a/5471032/3005
|
14
|
+
def which(cmd)
|
15
|
+
# PATHEXT contains the list of file extensions that Windows considers executable, semicolon separated.
|
16
|
+
# e.g. ".COM;.EXE;.BAT;.CMD"
|
17
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : []
|
18
|
+
exts << '' # Always have an empty string (= no file extension)
|
19
|
+
|
20
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
21
|
+
exts.each do |ext|
|
22
|
+
cmd_path = File.join(path, "#{cmd}#{ext}")
|
23
|
+
return cmd_path if Helper.executable?(cmd_path)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param command [String] The command to be executed
|
31
|
+
# @param print_all [Boolean] Do we want to print out the command output while running?
|
32
|
+
# @param print_command [Boolean] Should we print the command that's being executed
|
33
|
+
# @param error [Block] A block that's called if an error occurs
|
34
|
+
# @param prefix [Array] An array containing a prefix + block which might get applied to the output
|
35
|
+
# @param loading [String] A loading string that is shown before the first output
|
36
|
+
# @param suppress_output [Boolean] Should we print the command's output?
|
37
|
+
# @return [String] All the output as string
|
38
|
+
def execute(command: nil, print_all: false, print_command: true, error: nil, prefix: nil, loading: nil, suppress_output: false)
|
39
|
+
print_all = true if $verbose
|
40
|
+
prefix ||= {}
|
41
|
+
|
42
|
+
output = []
|
43
|
+
command = command.join(" ") if command.kind_of?(Array)
|
44
|
+
command = self.escape_characters_in_string(command)
|
45
|
+
UI.command(command) if print_command
|
46
|
+
|
47
|
+
if print_all && loading # this is only used to show the "Loading text"...
|
48
|
+
UI.command_output(loading)
|
49
|
+
end
|
50
|
+
|
51
|
+
begin
|
52
|
+
status = SctCore::SctPty.spawn(command) do |command_stdout, command_stdin, pid|
|
53
|
+
command_stdout.each do |l|
|
54
|
+
line = l.chomp
|
55
|
+
output << line
|
56
|
+
|
57
|
+
next unless print_all
|
58
|
+
|
59
|
+
# Prefix the current line with a string
|
60
|
+
prefix.each do |element|
|
61
|
+
line = element[:prefix] + line if element[:block] && element[:block].call(line)
|
62
|
+
end
|
63
|
+
|
64
|
+
UI.command_output(line) unless suppress_output
|
65
|
+
end
|
66
|
+
end
|
67
|
+
rescue => ex
|
68
|
+
# SctPty adds exit_status on to StandardError so every error will have a status code
|
69
|
+
status = ex.exit_status
|
70
|
+
|
71
|
+
# This could happen when the environment is wrong:
|
72
|
+
# > invalid byte sequence in US-ASCII (ArgumentError)
|
73
|
+
output << ex.to_s
|
74
|
+
o = output.join("\n")
|
75
|
+
puts(o)
|
76
|
+
if error
|
77
|
+
error.call(o, nil)
|
78
|
+
else
|
79
|
+
raise ex
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Exit status for build command, should be 0 if build succeeded
|
84
|
+
if status != 0
|
85
|
+
o = output.join("\n")
|
86
|
+
puts(o) unless suppress_output # the user has the right to see the raw output
|
87
|
+
UI.error("Exit status: #{status}")
|
88
|
+
if error
|
89
|
+
error.call(o, status)
|
90
|
+
else
|
91
|
+
UI.user_error!("Exit status: #{status}")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
return output.join("\n")
|
96
|
+
end
|
97
|
+
|
98
|
+
def escape_characters_in_string(string)
|
99
|
+
pattern = /(\'|\"|\.|\*|\/|\-|\\|\)|\$|\+|\(|\^|\?|\!|\~|\`)/
|
100
|
+
string.gsub(pattern){|match|"\\" + match}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
module
|
1
|
+
module SctCore
|
2
2
|
class Config
|
3
3
|
|
4
4
|
def self.dir
|
5
|
-
return "#{
|
5
|
+
return "#{SctCore::Helper.homePath}/.config/sct"
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.path
|
@@ -30,7 +30,7 @@ module Sct
|
|
30
30
|
|
31
31
|
contents = File.read(self.path)
|
32
32
|
|
33
|
-
return
|
33
|
+
return SctCore::Helper.to_hash(contents)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
File without changes
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class StandardError
|
2
|
+
def exit_status
|
3
|
+
return -1
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
module SctCore
|
8
|
+
class SctPtyError < StandardError
|
9
|
+
attr_reader :exit_status
|
10
|
+
def initialize(e, exit_status)
|
11
|
+
super(e)
|
12
|
+
set_backtrace(e.backtrace) if e
|
13
|
+
@exit_status = exit_status
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class SctPty
|
18
|
+
def self.spawn(command)
|
19
|
+
require 'pty'
|
20
|
+
PTY.spawn(command) do |command_stdout, command_stdin, pid|
|
21
|
+
begin
|
22
|
+
yield(command_stdout, command_stdin, pid)
|
23
|
+
rescue Errno::EIO
|
24
|
+
# Exception ignored intentionally.
|
25
|
+
# https://stackoverflow.com/questions/10238298/ruby-on-linux-pty-goes-away-without-eof-raises-errnoeio
|
26
|
+
# This is expected on some linux systems, that indicates that the subcommand finished
|
27
|
+
# and we kept trying to read, ignore it
|
28
|
+
ensure
|
29
|
+
begin
|
30
|
+
Process.wait(pid)
|
31
|
+
rescue Errno::ECHILD, PTY::ChildExited
|
32
|
+
# The process might have exited.
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
$?.exitstatus
|
37
|
+
rescue LoadError
|
38
|
+
require 'open3'
|
39
|
+
Open3.popen2e(command) do |command_stdin, command_stdout, p| # note the inversion
|
40
|
+
yield(command_stdout, command_stdin, p.value.pid)
|
41
|
+
|
42
|
+
command_stdin.close
|
43
|
+
command_stdout.close
|
44
|
+
p.value.exitstatus
|
45
|
+
end
|
46
|
+
rescue StandardError => e
|
47
|
+
# Wrapping any error in SctPtyError to allow
|
48
|
+
# callers to see and use $?.exitstatus that
|
49
|
+
# would usually get returned
|
50
|
+
raise SctPtyError.new(e, $?.exitstatus)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require_relative '../interface'
|
2
|
+
|
3
|
+
module SctCore
|
4
|
+
# Shell is the terminal output of things
|
5
|
+
# For documentation for each of the methods open `interface.rb`
|
6
|
+
class Shell < Interface
|
7
|
+
require 'tty-screen'
|
8
|
+
|
9
|
+
def log
|
10
|
+
$stdout.sync = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def writeToUser(message)
|
14
|
+
puts message
|
15
|
+
end
|
16
|
+
|
17
|
+
def error(message)
|
18
|
+
writeToUser(message.to_s.red)
|
19
|
+
end
|
20
|
+
|
21
|
+
def important(message)
|
22
|
+
writeToUser(message.to_s.yellow)
|
23
|
+
end
|
24
|
+
|
25
|
+
def success(message)
|
26
|
+
writeToUser(message.to_s.green)
|
27
|
+
end
|
28
|
+
|
29
|
+
def message(message)
|
30
|
+
writeToUser(message.to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def deprecated(message)
|
34
|
+
writeToUser(message.to_s.deprecated)
|
35
|
+
end
|
36
|
+
|
37
|
+
def command(message)
|
38
|
+
writeToUser("$ #{message}".cyan)
|
39
|
+
end
|
40
|
+
|
41
|
+
def command_output(message)
|
42
|
+
actual = (message.split("\r").last || "") # as clearing the line will remove the `>` and the time stamp
|
43
|
+
actual.split("\n").each do |msg|
|
44
|
+
# prefix = msg.include?("▸") ? "" : "▸ "
|
45
|
+
prefix = ""
|
46
|
+
writeToUser(prefix + "" + msg.magenta)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def verbose(message)
|
51
|
+
message.to_s if $verbose
|
52
|
+
end
|
53
|
+
|
54
|
+
def header(message)
|
55
|
+
format = format_string
|
56
|
+
if message.length + 8 < TTY::Screen.width - format.length
|
57
|
+
message = "--- #{message} ---"
|
58
|
+
i = message.length
|
59
|
+
else
|
60
|
+
i = TTY::Screen.width - format.length
|
61
|
+
end
|
62
|
+
success("-" * i)
|
63
|
+
success(message)
|
64
|
+
success("-" * i)
|
65
|
+
end
|
66
|
+
|
67
|
+
def content_error(content, error_line)
|
68
|
+
error_line = error_line.to_i
|
69
|
+
return unless error_line > 0
|
70
|
+
|
71
|
+
contents = content.split(/\r?\n/).map(&:chomp)
|
72
|
+
|
73
|
+
start_line = error_line - 2 < 1 ? 1 : error_line - 2
|
74
|
+
end_line = error_line + 2 < contents.length ? error_line + 2 : contents.length
|
75
|
+
|
76
|
+
Range.new(start_line, end_line).each do |line|
|
77
|
+
str = line == error_line ? " => " : " "
|
78
|
+
str << line.to_s.rjust(Math.log10(end_line) + 1)
|
79
|
+
str << ":\t#{contents[line - 1]}"
|
80
|
+
error(str)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
#####################################################
|
85
|
+
# @!group Errors: Inputs
|
86
|
+
#####################################################
|
87
|
+
|
88
|
+
def interactive?
|
89
|
+
interactive = true
|
90
|
+
interactive = false if $stdout.isatty == false
|
91
|
+
return interactive
|
92
|
+
end
|
93
|
+
|
94
|
+
def input(message)
|
95
|
+
verify_interactive!(message)
|
96
|
+
ask("#{format_string}#{message.to_s.yellow}").to_s.strip
|
97
|
+
end
|
98
|
+
|
99
|
+
def confirm(message)
|
100
|
+
verify_interactive!(message)
|
101
|
+
agree("#{format_string}#{message.to_s.yellow} (y/n)", true)
|
102
|
+
end
|
103
|
+
|
104
|
+
def select(message, options)
|
105
|
+
verify_interactive!(message)
|
106
|
+
|
107
|
+
important(message)
|
108
|
+
choose(*options)
|
109
|
+
end
|
110
|
+
|
111
|
+
def password(message)
|
112
|
+
verify_interactive!(message)
|
113
|
+
|
114
|
+
ask("#{format_string}#{message.to_s.yellow}") { |q| q.echo = "*" }
|
115
|
+
end
|
116
|
+
|
117
|
+
def user_error!(error_message, options = {})
|
118
|
+
writeToUser(error_message.yellow)
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def verify_interactive!(message)
|
124
|
+
return if interactive?
|
125
|
+
important(message)
|
126
|
+
crash!("Could not retrieve response as sct runs in non-interactive mode")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|