sesh 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/sesh +192 -0
  3. metadata +46 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 471da2a6d1c23302beb0858f3bcaf8dde2ea0730
4
+ data.tar.gz: 0c84359f0c8f57327e59cd7a81d4ad86187f56c4
5
+ SHA512:
6
+ metadata.gz: 478ed2e28e910409295fc525752f3d1f1a76c88d8e78b2d66874eb1195c226a6beff0b334db0be9e0abbffaa4e6ff03c4e2a7b912062f0fecbc5250305b03812
7
+ data.tar.gz: b308849d0a53fdf43fa86cc1e97c278c497cece0e2958b32ac8eefe562550c3a17587cbfe069bb1e6c14f06ca065348ed62de5c93881dc48a2876459057b5441
data/bin/sesh ADDED
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.include? '-h' or ARGV.include? '--help' then puts <<-HELP
4
+ Sesh: remote background sessions powered by tmux and tmuxinator.
5
+ Runs a headless tmuxinator session for remote slave machines to connect to.
6
+
7
+ Usage: #{File.basename $0} [command] [project]
8
+
9
+ Commands:
10
+
11
+ sesh new Create a new tmuxinator configuration.
12
+ sesh start [project_name] Start a Sesh session for a project.
13
+ sesh stop [project_name] Stop a Sesh session for a project.
14
+ sesh list List running Sesh sessions on this machine.
15
+ sesh connect [project] user@host Connect as a slave to a remote Sesh session.
16
+ sesh enslave [project] user@host Connect a slave to a local Sesh session.
17
+
18
+ HELP
19
+ exit; end
20
+
21
+ def warn(msg) $stderr.puts msg end
22
+ def fatal(msg) $stderr.puts msg; $stderr.puts; exit 1 end
23
+ def debug(msg) $stderr.puts "> #{msg}" end
24
+
25
+ @command = ARGV[0]
26
+ @options = ARGV[1..-1] || []
27
+ # debug("Options received: #{@options}") if @options.any?
28
+
29
+ def get_project_name
30
+ if @options.any?
31
+ pn_opt = if %w(connect enslave).include? @command
32
+ @options.shift if @options[1]
33
+ else
34
+ @options[0]
35
+ end
36
+ if pn_opt
37
+ pn_opt_path = File.expand_path("~/.tmuxinator/#{pn_opt}.yml")
38
+ return pn_opt if File.exist? pn_opt_path
39
+ end
40
+ end
41
+ `printf '%q\n' "${PWD##*/}"`.strip
42
+ end
43
+ @project_name = get_project_name
44
+
45
+ def get_local_username
46
+ `echo $USER`.strip
47
+ end
48
+ def get_local_hostname
49
+ `scutil --get LocalHostName`.strip.downcase + '.local'
50
+ end
51
+ @local_ssh_addr = "#{get_local_username}@#{get_local_hostname}"
52
+
53
+ @socket = "/tmp/#{@project_name}.sock"
54
+
55
+ def project_name_matcher
56
+ pn = @project_name.gsub '-', '\-'
57
+ "[t]mux.*[#{pn[0]}]#{pn[1..-1]}"
58
+ end
59
+
60
+ def already_running?
61
+ output = `ps aux | grep "#{project_name_matcher}"`.strip
62
+ output.length > 0
63
+ end
64
+
65
+ def format_command(command) command.gsub(/\ [ ]+/, ' ').strip end
66
+ def format_and_run_command(command) `#{format_command(command)}`.strip end
67
+
68
+ def issue_server_start_command!
69
+ `tmux -vvvv -S "#{@socket}" new-session -d "env TMUX='' mux start #{@project_name}"`
70
+ end
71
+
72
+ def issue_server_stop_command!
73
+ `pkill -f "#{project_name_matcher}"`
74
+ end
75
+
76
+ def connection_command(local=false)
77
+ local_command = "tmux -S #{@socket} a"
78
+ return local_command if local
79
+ "ssh #{@local_ssh_addr} -t '#{local_command}'"
80
+ end
81
+
82
+ def enter_slave_mode_command(local=false)
83
+ tell_iterm_app = 'tell application "iTerm"'
84
+ tell_iterm_process = 'tell application "System Events" to tell process "iTerm"'
85
+ format_command <<-BASH
86
+ osascript \
87
+ -e '#{tell_iterm_app} to activate' \
88
+ -e '#{tell_iterm_process} to keystroke \"n\" using command down' \
89
+ -e 'delay 1' \
90
+ -e '#{tell_iterm_app} to tell session -1 of current terminal to \
91
+ write text "#{connection_command(local).gsub("'", '\\\\\'')}"' \
92
+ -e '#{tell_iterm_process} to keystroke return using command down'
93
+ BASH
94
+ end
95
+
96
+ def show_progress_until(condition_lambda, timeout=10)
97
+ started_progress_at = Time.now
98
+ return true if condition_lambda.call
99
+ print '> '
100
+ until condition_lambda.call or Time.now - started_progress_at > timeout
101
+ print '.'
102
+ $stdout.flush
103
+ sleep 0.5
104
+ end
105
+ puts
106
+ return condition_lambda.call
107
+ end
108
+
109
+ if @command
110
+ case @command
111
+ when 'start'
112
+ fatal("Sesh project '#{@project_name}' is already running!") if already_running?
113
+ debug "Starting Sesh project '#{@project_name}'..."
114
+ output = issue_server_start_command!
115
+ success = show_progress_until ->{ already_running? }
116
+ if success
117
+ sleep 1
118
+ if $? && already_running?
119
+ debug 'Sesh started successfully.'
120
+ debug "To connect: #{connection_command}"
121
+ puts
122
+ else
123
+ fatal 'Sesh failed to start!'
124
+ end
125
+ else
126
+ fatal 'Sesh failed to start after ten seconds!'
127
+ end
128
+ when 'stop'
129
+ fatal("Sesh project '#{@project_name}' is not running!") unless already_running?
130
+ debug "Stopping Sesh project '#{@project_name}'..."
131
+ output = issue_server_stop_command!
132
+ success = show_progress_until ->{ !already_running? }
133
+ if success && $?
134
+ debug 'Sesh stopped successfully.'
135
+ puts
136
+ else
137
+ fatal 'Sesh failed to stop after ten seconds!'
138
+ end
139
+ when 'restart'
140
+ fatal("Sesh project '#{@project_name}' is not running!") unless already_running?
141
+ puts `sesh stop #{@project_name} #{@options if @options.any?}`.strip
142
+ sleep(0.5)
143
+ puts `sesh start #{@project_name} #{@options if @options.any?}`.strip
144
+ when 'new'
145
+ command = "env EDITOR='vim' tmuxinator new #{@project_name}"
146
+ output = exec command
147
+ puts
148
+ when 'list'
149
+ output = format_and_run_command <<-BASH
150
+ ps aux | grep tmux | grep "env TMUX='' mux start" \
151
+ | grep -v "[g]rep" | sed -e "s/.*mux start \\(.*\\)/\\1/"
152
+ BASH
153
+ running_projects = output.split("\n")
154
+ pcount = running_projects.count
155
+ if pcount > 0
156
+ puts "#{pcount} project#{pcount>1 ? 's':''} currently running:"
157
+ puts running_projects
158
+ puts
159
+ else
160
+ fatal "There are no Sesh projects currently running."
161
+ end
162
+ when 'connect'
163
+ slave_address = @options[0]
164
+ if (is_local=slave_address.nil?)
165
+ slave_address = @local_ssh_addr
166
+ fatal("Sesh project '#{@project_name}' is not running!") unless already_running?
167
+ end
168
+ command = enter_slave_mode_command(is_local)
169
+ puts command
170
+ puts `#{command}`.strip
171
+ when 'enslave'
172
+ fatal("Sesh project '#{@project_name}' is not running!") unless already_running?
173
+ fatal("You must specify a machine to enslave! Eg: user@ip") unless @options.any?
174
+ slave_address = @options[0]
175
+ debug "Attempting to connect #{slave_address} to Sesh project '#{@project_name}'..."
176
+ output = format_and_run_command <<-BASH
177
+ ssh #{slave_address} "#{enter_slave_mode_command.gsub('"', '\"')}"
178
+ BASH
179
+ puts output
180
+ if $?
181
+ debug "Sesh client connected successfully."
182
+ puts
183
+ else
184
+ fatal 'Sesh client failed to start.'
185
+ end
186
+ else
187
+ fatal "Command not recognized!"
188
+ end
189
+ exit 0
190
+ end
191
+
192
+ fatal 'You must specify a command.'
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sesh
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - MacKinley Smith
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-17 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Remote background sessions powered by tmux and tmuxinator.
14
+ email: smithmackinley@gmail.com
15
+ executables:
16
+ - sesh
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/sesh
21
+ homepage: http://rubygems.org/gems/sesh
22
+ licenses:
23
+ - GNU GPLv3
24
+ metadata: {}
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubyforge_project:
41
+ rubygems_version: 2.2.2
42
+ signing_key:
43
+ specification_version: 4
44
+ summary: Sesh
45
+ test_files: []
46
+ has_rdoc: