sesh 0.0.1

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.
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: