Module: TrainSH::Mixin::BuiltInCommands

Defined in:
lib/trainsh/mixin/builtin_commands.rb

Constant Summary collapse

BUILTIN_PREFIX =
'builtincmd_'.freeze
SESSION_PATH_REGEX =
%r{(/@(\d+):(/.*)$/)}.freeze

Instance Method Summary collapse

Instance Method Details

#builtin_commandsObject



9
10
11
# File 'lib/trainsh/mixin/builtin_commands.rb', line 9

def builtin_commands
  methods.sort.filter { |method| method.to_s.start_with? BUILTIN_PREFIX }.map { |method| method.to_s.delete_prefix BUILTIN_PREFIX }
end

#builtincmd_clear_history(_args = nil) ⇒ Object



13
14
15
# File 'lib/trainsh/mixin/builtin_commands.rb', line 13

def builtincmd_clear_history(_args = nil)
  Readline::HISTORY.clear
end

#builtincmd_connect(url = nil) ⇒ Object



17
18
19
20
21
22
23
24
# File 'lib/trainsh/mixin/builtin_commands.rb', line 17

def builtincmd_connect(url = nil)
  if url.nil? || url.strip.empty?
    show_error 'Expecting session url, e.g. `!connect docker://123456789abcdef0`'
    return false
  end

  use_session(url)
end

#builtincmd_copy(src = nil, dst = nil) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/trainsh/mixin/builtin_commands.rb', line 26

def builtincmd_copy(src = nil, dst = nil)
  src_id, src_path = src&.match(SESSION_PATH_REGEX)&.captures
  dst_id, dst_path = dst&.match(SESSION_PATH_REGEX)&.captures
  unless src && dst && src_id && dst_id && src_path && dst_path
    show_error 'Expecting source and destination, e.g. `!copy @0:/etc/hosts @1:/home/ubuntu/old_hosts'
    return
  end

  src_session = session(src_id)
  dst_session = session(dst_id)
  unless src_session && dst_session
    show_error 'Expecting valid session identifiers. Check available sessions via !sessions'
    return
  end

  content = src_session.file(src_path)
  dst_session.file(dst_path).content = content

  show_message "Copied #{content.size} bytes successfully"
end

#builtincmd_detect(_args = nil) ⇒ Object



47
48
49
# File 'lib/trainsh/mixin/builtin_commands.rb', line 47

def builtincmd_detect(_args = nil)
  __detect
end

#builtincmd_download(remote_path = nil, local_path = nil) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/trainsh/mixin/builtin_commands.rb', line 51

def builtincmd_download(remote_path = nil, local_path = nil)
  if remote_path.nil? || local_path.nil?
    show_error 'Expecting remote path and local path, e.g. `!download /etc/passwd /home/ubuntu`'
    return false
  end

  return unless train_mutable?

  session.download(remote_path, local_path)

  show_message "Downloaded #{remote_path} successfully"
rescue NotImplementedError
  show_error 'Backend for session does not implement file operations'
rescue StandardError => e
  show_error "Error occured: #{e.message}"
end

#builtincmd_edit(path = nil) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/trainsh/mixin/builtin_commands.rb', line 68

def builtincmd_edit(path = nil)
  if path.nil? || path.strip.empty?
    show_error 'Expecting remote path, e.g. `!less /tmp/somefile.txt`'
    return false
  end

  tempfile = read_file(path)
  old_content = File.read(tempfile.path)

  localeditor = ENV['EDITOR'] || ENV['VISUAL'] || 'vi' # TODO: configuration, Windows, ...
  show_message format('Using local editor `%<editor>s` for %<tempfile>s', editor: localeditor, tempfile: tempfile.path)

  system("#{localeditor} #{tempfile.path}")
  new_content = File.read(tempfile.path)

  if new_content == old_content
    show_message 'No changes detected'
  else
    write_file(path, new_content)

    show_message "Wrote #{new_content.size} bytes successfully"
  end

  tempfile.unlink
rescue NotImplementedError
  show_error 'Backend for session does not implement file operations'
rescue StandardError => e
  show_error "Error occured: #{e.message}"
end

#builtincmd_env(_args = nil) ⇒ Object



98
99
100
# File 'lib/trainsh/mixin/builtin_commands.rb', line 98

def builtincmd_env(_args = nil)
  puts session.env
end

#builtincmd_help(_args = nil) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/trainsh/mixin/builtin_commands.rb', line 102

def builtincmd_help(_args = nil)
  show_message <<~HELP
    Unprefixed commands get sent to the remote host of the active session.

    Commands with a prefix of `@n` with n being a number will be executed on the specified session. For a list of sessions check `!sessions`.

    Commands with a prefix of `.` get executed locally.

    Builtin commands are prefixed with `!`:
  HELP

  builtin_commands.each { |cmd| show_message " !#{cmd}" }
end

#builtincmd_history(_args = nil) ⇒ Object



136
137
138
# File 'lib/trainsh/mixin/builtin_commands.rb', line 136

def builtincmd_history(_args = nil)
  puts Readline::HISTORY.to_a
end

#builtincmd_host(_args = nil) ⇒ Object



140
141
142
# File 'lib/trainsh/mixin/builtin_commands.rb', line 140

def builtincmd_host(_args = nil)
  show_message session.host
end

#builtincmd_ping(_args = nil) ⇒ Object



144
145
146
147
148
# File 'lib/trainsh/mixin/builtin_commands.rb', line 144

def builtincmd_ping(_args = nil)
  session.run_idle

  show_message format('Ping: %<ping>dms', ping: session.ping)
end

#builtincmd_pry(_args = nil) ⇒ Object

rubocop:disable Lint/Debugger



151
152
153
154
# File 'lib/trainsh/mixin/builtin_commands.rb', line 151

def builtincmd_pry(_args = nil)
  require 'pry' unless defined?(binding.pry)
  binding.pry
end

#builtincmd_pwd(_args = nil) ⇒ Object

rubocop:enable Lint/Debugger



157
158
159
# File 'lib/trainsh/mixin/builtin_commands.rb', line 157

def builtincmd_pwd(_args = nil)
  show_message session.pwd
end

#builtincmd_read(path = nil) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/trainsh/mixin/builtin_commands.rb', line 116

def builtincmd_read(path = nil)
  if path.nil? || path.strip.empty?
    show_error 'Expecting remote path, e.g. `!read /tmp/somefile.txt`'
    return false
  end

  tempfile = read_file(path)
  return false unless tempfile

  localpager = ENV['PAGER'] || 'less' # TODO: configuration, Windows, ...
  show_message format('Using local pager `%<pager>s` for %<tempfile>s', pager: localpager, tempfile: tempfile.path)
  system("#{localpager} #{tempfile.path}")

  tempfile.unlink
rescue NotImplementedError
  show_error 'Backend for session does not implement file operations'
rescue StandardError => e
  show_error "Error occured: #{e.message}"
end

#builtincmd_reconnect(_args = nil) ⇒ Object



161
162
163
# File 'lib/trainsh/mixin/builtin_commands.rb', line 161

def builtincmd_reconnect(_args = nil)
  session.reconnect
end

#builtincmd_session(session_id = nil) ⇒ Object



173
174
175
176
177
178
179
180
181
# File 'lib/trainsh/mixin/builtin_commands.rb', line 173

def builtincmd_session(session_id = nil)
  session_id = validate_session_id(session_id)
  return if session_id.nil?

  # TODO: Make this more pretty
  session_url = @sessions[session_id].url

  use_session(session_url)
end

#builtincmd_sessions(_args = nil) ⇒ Object



165
166
167
168
169
170
171
# File 'lib/trainsh/mixin/builtin_commands.rb', line 165

def builtincmd_sessions(_args = nil)
  show_message 'Active sessions:'

  @sessions.each_with_index do |session, idx|
    show_message format('[%<idx>d] %<session>s', idx: idx, session: session.url)
  end
end

#builtincmd_upload(local_path = nil, remote_path = nil) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/trainsh/mixin/builtin_commands.rb', line 183

def builtincmd_upload(local_path = nil, remote_path = nil)
  if remote_path.nil? || local_path.nil?
    show_error 'Expecting remote path and local path, e.g. `!download /home/ubuntu/passwd /etc'
    return false
  end

  return unless train_mutable?

  session.upload(local_path, remote_path)

  show_message "Uploaded to #{remote_path} successfully"
rescue ::Errno::ENOENT
  show_error "Local file/directory '#{local_path}' does not exist"
rescue NotImplementedError
  show_error 'Backend for session does not implement upload operation'
rescue StandardError => e
  show_error "Error occured: #{e.message}"
end