Module: TmuxConnector
- Defined in:
- lib/tmux-connector.rb,
lib/tmux-connector/host.rb,
lib/tmux-connector/layout.rb,
lib/tmux-connector/session.rb,
lib/tmux-connector/version.rb,
lib/tmux-connector/tmux_handler.rb,
lib/tmux-connector/commands/list.rb,
lib/tmux-connector/commands/send.rb,
lib/tmux-connector/commands/start.rb,
lib/tmux-connector/config_handler.rb,
lib/tmux-connector/command_handler.rb,
lib/tmux-connector/commands/delete.rb,
lib/tmux-connector/commands/resume.rb,
lib/tmux-connector/persistence_handler.rb
Defined Under Namespace
Classes: Delete, FakeHost, Host, Layout, List, Pane, Resume, Send, Session, Start, TmuxSession
Constant Summary
collapse
- TCON_DOC =
<<HERE
tcon enables establishing connections (ssh) to multiple servers and executing
commands on those servers. The sessions can be persisted (actually recreated)
even after computer restarts. Complex sessions with different layouts for
different kinds of servers can be easily created.
Usage:
tcon start ( <config-file> | --quick-session=<qs-args> )
[--ssh-config=<file>] [--session-name=<name>]
[--purpose=<description>]
tcon resume <session-name>
tcon delete (<session-name> | --all)
tcon list
tcon send <session-name> ( <command> | --command-file=<file> )
[ --server-filter=<filter> | --group-filter=<regex>
| --filter=<regex> | --window=<index> ]
[--verbose]
tcon --help
tcon --version
Options:
<config-file> Path to configuration file. Configuration file
describes how new session is started. YAML.
<qs-args> Arguments needed to start a quick session.
<session-name> Name to identify the session. Must be unique.
<command> Command to be executed on remote server[s].
<regex> String that represents valid Ruby regex.
<index> 0-based index.
<filter> Filter consisting of a valid ruby regex and
optionally of a special predicate.
For more information see README file.
-q --quick-session=qs-args Start the seesion without a configuration file.
Specify necessary argumenst instead.
-s --ssh-config=file Path to ssh config file. [default: ~/.ssh/config]
-n --session-name=name Name of the session.
-p --purpose=description Description of session's purpose.
--all Delete all existing sessions.
-f --server-filter=filter Filter to select a subset of the servers via
host names.
-g --group-filter=regex Filter to select a subset of the servers via
group membership.
-r --filter=regex Filter to select a subset of the servers via
host names or group membership.
Combines --server-filter and --group-filter.
-w --window=index Select a window via (0-based) index.
-c --command-file=file File containing the list of commands to be
executed on remote server[s].
-v --verbose Report how many servers were affected by the
send command.
-h --help Show this screen.
--version Show version.
HERE
- QUICK_GROUP_ID =
'quick_group_id'
- VERSION =
"1.0.8"
- DEFAULT_CONFIG_FILE =
'lib/tmux-connector/default_config.yml'
- COMMANDS =
%w[ start resume delete list send ]
- BASE_DIR =
File.expand_path '~/.tmux-connector'
- MAIN_FILE =
File.join BASE_DIR, '_sessions.yml'
- SESSION_BASE_NAME =
"s#"
Class Method Summary
collapse
Class Method Details
.delete_all ⇒ Object
42
43
44
|
# File 'lib/tmux-connector/persistence_handler.rb', line 42
def self.delete_all()
FileUtils.rm_rf BASE_DIR
end
|
.delete_all_tmux_sessions ⇒ Object
7
8
9
10
11
|
# File 'lib/tmux-connector/tmux_handler.rb', line 7
def self.delete_all_tmux_sessions()
sessions_list = %x( tmux list-sessions 2> /dev/null)
sessions = sessions_list.scan(/^([^:]+): /).map(&:first)
sessions.each { |e| delete_tmux_session e }
end
|
.delete_session(session_name) ⇒ Object
60
61
62
63
64
65
66
67
68
|
# File 'lib/tmux-connector/persistence_handler.rb', line 60
def self.delete_session(session_name)
data = list_sessions
raise "session not found: '#{ session_name }'" if data[session_name].nil?
file = data[session_name]['file']
data.delete session_name
open(MAIN_FILE, 'w') { |f| f.write data.to_yaml }
File.delete(file) rescue nil
end
|
.delete_tmux_session(name) ⇒ Object
2
3
4
5
|
# File 'lib/tmux-connector/tmux_handler.rb', line 2
def self.delete_tmux_session(name)
system "tmux detach -s #{ name } &> /dev/null"
system "tmux kill-session -t #{ name } &> /dev/null"
end
|
.detect_command(args) ⇒ Object
18
19
20
21
|
# File 'lib/tmux-connector/command_handler.rb', line 18
def self.detect_command(args)
COMMANDS.each { |e| return e if args[e] }
raise 'unkonwn command'
end
|
.expand_layout(config) ⇒ Object
44
45
46
47
48
49
50
|
# File 'lib/tmux-connector/config_handler.rb', line 44
def self.expand_layout(config)
if config['tmux']
config['tmux']['max-panes'] ||= 9
else
config['custom']['panes-flow'] ||= 'horizontal'
end
end
|
.get_class(command) ⇒ Object
23
24
25
26
|
# File 'lib/tmux-connector/command_handler.rb', line 23
def self.get_class(command)
class_name = command.split('-').map { |e| e.capitalize }.join
return TmuxConnector.const_get class_name
end
|
.get_config(config_file) ⇒ Object
7
8
9
10
11
|
# File 'lib/tmux-connector/config_handler.rb', line 7
def self.get_config(config_file)
config = read_config config_file
process_config!(config) rescue raise 'configuration file parsing failed'
return config
end
|
.get_new_session_name(args) ⇒ Object
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
# File 'lib/tmux-connector/persistence_handler.rb', line 77
def self.get_new_session_name(args)
specified = args["--session-name"]
if File.exists? MAIN_FILE
existing_names = list_sessions.keys
if specified
raise "session with name '#{ specified }' already exists." if existing_names.include? specified
name = specified
else
re = /#{ SESSION_BASE_NAME }(\d+)/
last_index = existing_names.reduce(0) do |acc, e|
index = ( e.match(re)[1].to_i rescue 0 )
[ acc, index].max
end
name = "#{ SESSION_BASE_NAME }#{ last_index + 1 }"
end
else
name = specified || "#{ SESSION_BASE_NAME }1"
end
return name
end
|
.list_sessions(options = {}) ⇒ Object
70
71
72
73
74
75
|
# File 'lib/tmux-connector/persistence_handler.rb', line 70
def self.list_sessions(options={})
unless options[:suppress_error]
raise "session file (#{ MAIN_FILE }) not found" unless File.exist? MAIN_FILE
end
return ( YAML.load_file(MAIN_FILE) rescue {} ) || {}
end
|
.load_session(session_name) ⇒ Object
22
23
24
25
26
27
28
29
30
31
32
|
# File 'lib/tmux-connector/persistence_handler.rb', line 22
def self.load_session(session_name)
data = list_sessions
raise "session not found: '#{ session_name }'" if data[session_name].nil?
file = data[session_name]['file']
raise "session file (#{ file }) not found" unless File.exist? file
session = nil
open(file, 'rb') { |f| session = Marshal.load f }
return session
end
|
.main(input_args) ⇒ Object
61
62
63
64
65
66
67
68
69
70
|
# File 'lib/tmux-connector.rb', line 61
def self.main(input_args)
begin
args = Docopt.docopt TCON_DOC, argv: input_args, version: VERSION
process_command args
rescue Docopt::Exit => e
puts e.message
rescue => e
puts "Something went wrong: #{ e.message }"
end
end
|
.prepare_if_necessary ⇒ Object
34
35
36
37
38
39
40
|
# File 'lib/tmux-connector/persistence_handler.rb', line 34
def self.prepare_if_necessary()
unless File.exists?(BASE_DIR) && File.directory?(BASE_DIR)
Dir.mkdir(BASE_DIR)
end
FileUtils.touch MAIN_FILE unless File.exists? MAIN_FILE
end
|
.process_command(args) ⇒ Object
11
12
13
14
15
16
|
# File 'lib/tmux-connector/command_handler.rb', line 11
def self.process_command(args)
command = detect_command args
klass = get_class command
command_obj = klass.new args
command_obj.run
end
|
.process_config!(config) ⇒ Object
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
# File 'lib/tmux-connector/config_handler.rb', line 21
def self.process_config!(config)
config['regex'] = Regexp.new config['regex']
config['reject-regex'] = Regexp.new(config['reject-regex']) if config['reject-regex']
if (c = config['name'])
c['regex-ignore-parts'] ||= []
c['separator'] ||= '-'
c['prefix'] ||= ''
end
layout = config['layout'] ||= {}
if layout['default'].nil?
layout['default'] = {
'tmux' => { 'layout' => 'tiled' }
}
end
expand_layout layout['default']
if layout['group-layouts']
layout['group-layouts'].each { |k, v| expand_layout v }
end
end
|
.read_config(config_file) ⇒ Object
13
14
15
16
17
18
19
|
# File 'lib/tmux-connector/config_handler.rb', line 13
def self.read_config(config_file)
full_path = File.expand_path config_file
raise "configuration file (#{config_file}) not found" unless File.exist? full_path
config = YAML.load_file full_path
return config
end
|
.save_session(session_name, session_obj) ⇒ Object
9
10
11
12
13
14
15
16
17
18
19
20
|
# File 'lib/tmux-connector/persistence_handler.rb', line 9
def self.save_session(session_name, session_obj)
prepare_if_necessary
created = Time.now.strftime('%Y-%m-%d %H:%M')
file = File.join(BASE_DIR, "#{ session_name.gsub(/[^a-zA-Z0-9_-]+/, '-') }.bin")
file.sub!('.bin', "__#{ created.gsub(/[ :]/, '_') }.bin") if File.exists? file
update_main_file(session_name, created, file, session_obj.args['--purpose'])
open(file, 'wb') { |f| Marshal.dump session_obj, f }
end
|
.update_main_file(session_name, created, file, purpose) ⇒ Object
46
47
48
49
50
51
52
53
54
55
56
57
58
|
# File 'lib/tmux-connector/persistence_handler.rb', line 46
def self.update_main_file(session_name, created, file, purpose)
data = list_sessions
data[session_name] = {
'created' => created,
'file' => file
}
data[session_name]['purpose'] = purpose if purpose
open(MAIN_FILE, 'w') { |f| f.write data.to_yaml }
return file
end
|