class TrainSH::Cli
Constants
- EXIT_COMMANDS
- INTERACTIVE_COMMANDS
Public Class Methods
exit_on_failure?()
click to toggle source
add_runtime_options!
# File lib/trainsh/cli.rb, line 24 def self.exit_on_failure? true end
Public Instance Methods
__detect()
click to toggle source
TODO def __detect_url(url)
url || kitchen_url || ENV['target']
end
# File lib/trainsh/cli.rb, line 53 def __detect raise 'No session in __detect' unless session platform = session.platform say format('Platform: %<title>s %<release>s (%<arch>s)', title: platform.title, release: platform.release, arch: platform.arch) say format('Hierarchy: %<hierarchy>s', hierarchy: platform.family_hierarchy.reverse.join('/')) say 'Measuring ping over connection...' # Idle command will also trigger discovery commands on first run session.run_idle say format('Ping: %<ping>dms', ping: session.ping) if session.ping end
__disconnect()
click to toggle source
# File lib/trainsh/cli.rb, line 42 def __disconnect session.close say 'Disconnected' end
__print_version()
click to toggle source
# File lib/trainsh/cli.rb, line 30 def __print_version say "#{TrainSH::PRODUCT} #{TrainSH::VERSION} (Ruby #{RUBY_VERSION}-#{RUBY_PLATFORM})" end
auto_complete(partial)
click to toggle source
# File lib/trainsh/cli.rb, line 157 def auto_complete(partial) choices = [] choices.concat(builtin_commands.map { |cmd| "!#{cmd.tr('_', '-')}" }) choices.concat(sessions.map { |session_id| "@#{session_id}" }) choices.concat %w[!!!] choices.filter { |choice| choice.start_with? partial } end
connect(url)
click to toggle source
# File lib/trainsh/cli.rb, line 185 def connect(url) exit unless use_session(url) say format('Connected to %<url>s', url: session.url).bold say 'Running platform detection...' __detect # History persistence (TODO: Extract) user_conf_dir = File.join(ENV['HOME'], TrainSH::USER_CONF_DIR) history_file = File.join(user_conf_dir, 'history') FileUtils.mkdir_p(user_conf_dir) FileUtils.touch(history_file) File.readlines(history_file).each { |line| Readline::HISTORY.push line.strip } at_exit { history_file = File.join(user_conf_dir, 'history') File.open(history_file, 'w') { |f| f.write Readline::HISTORY.to_a.join("\n") } } # Catch Ctrl-C and exit cleanly stty_save = `stty -g`.chomp trap('INT') do puts '^C' system('stty', stty_save) exit end # Autocompletion Readline.completion_proc = method(:auto_complete).to_proc Readline.completion_append_character = ' ' while (input = Readline.readline(prompt, true)) if input.empty? Readline::HISTORY.pop next end Readline::HISTORY.pop if input.start_with? '!history' break if exit_command? input next if interactive_command? input execute input end end
detect(url)
click to toggle source
# File lib/trainsh/cli.rb, line 238 def detect(url) exit unless use_session(url) __detect end
execute(input)
click to toggle source
# File lib/trainsh/cli.rb, line 78 def execute(input) case input[0] when '.' execute_locally input[1..] when '!' execute_builtin input[1..] when '@' execute_via_session input[1..] else execute_via_train input end end
execute_builtin(input)
click to toggle source
# File lib/trainsh/cli.rb, line 104 def execute_builtin(input) cmd, *args = input.split ruby_cmd = cmd.tr('-', '_') if builtin_commands.include? ruby_cmd send("#{BUILTIN_PREFIX}#{ruby_cmd}".to_sym, *args) else say format('Unknown built-in "%<cmd>s"', cmd: cmd) end end
execute_locally(input)
click to toggle source
# File lib/trainsh/cli.rb, line 91 def execute_locally(input) system(input) end
execute_via_session(input)
click to toggle source
# File lib/trainsh/cli.rb, line 116 def execute_via_session(input) session_id, *data = input.split session_id = validate_session_id(session_id) if session_id.nil? say 'Expecting valid session id, e.g. `!session 2`'.red return end input = data.join(' ') if input.empty? say 'Specify command to execute, e.g. `@0 ls`' return end execute_via_train(input, session_id) end
execute_via_train(input, session_id = current_session_id)
click to toggle source
# File lib/trainsh/cli.rb, line 95 def execute_via_train(input, session_id = current_session_id) return if interactive_command? input command_result = @sessions[session_id].run(input) say command_result.stdout unless command_result.stdout && command_result.stdout.empty? say command_result.stderr.red unless command_result.stderr && command_result.stderr.empty? end
exit_command?(cmd)
click to toggle source
# File lib/trainsh/cli.rb, line 140 def exit_command?(cmd) EXIT_COMMANDS.include? cmd end
interactive_command?(cmd)
click to toggle source
# File lib/trainsh/cli.rb, line 134 def interactive_command?(cmd) return unless INTERACTIVE_COMMANDS.any? { |banned| cmd.start_with? banned } say 'Cannot execute interactive commands on non-tty sessions'.red end
list_transports()
click to toggle source
# File lib/trainsh/cli.rb, line 251 def list_transports # TODO: Train only lazy-loads and does not have a full registry # https://github.com/inspec/train/blob/be90ca53ea1c1e8aa7439c504fbee86f4b399d83/lib/train.rb#L38-L61 # TODO: Filter for only "OS" transports as well transports = %w[local ssh winrm docker] say "Available transports: #{transports.sort.join(', ')}" end
prompt()
click to toggle source
# File lib/trainsh/cli.rb, line 144 def prompt exitcode = current_session.exitcode exitcode_prefix = exitcode.zero? ? 'OK '.green : format('E%02d ', exitcode).red format(::TrainSH::PROMPT, exitcode: exitcode, exitcode_prefix: exitcode_prefix, session_id: current_session_id, backend: current_session.backend || 'unknown', host: current_session.host || 'unknown', path: current_session.pwd || '?') end
target_detectors()
click to toggle source
# File lib/trainsh/cli.rb, line 72 def target_detectors Dir[File.join(__dir__, 'lib', '*.rb')].sort.each { |file| require file } TrainSH::Detectors::TargetDetector.descendants end