pair 0.0.1 → 0.0.2

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.
data/.gitignore CHANGED
@@ -13,3 +13,4 @@ doc
13
13
 
14
14
  # jeweler generated
15
15
  pkg
16
+ *.gem
@@ -1,21 +1,22 @@
1
1
  module Pair
2
2
  class Session
3
+ # TODO replace with authorized_keys gem
3
4
  class AuthorizedKeysFile
4
5
  ACCESS_TYPE = "type"
5
6
  KEYS = "keys"
6
7
 
7
8
  attr_accessor :member_keys
8
- attr_accessor :session
9
+ attr_accessor :attach_command
9
10
  attr_accessor :key_file_path
10
11
 
11
- def initialize(member_keys = {}, session)
12
- self.member_keys = member_keys
13
- self.session = session
14
- self.key_file_path = File.expand_path("~/.ssh/authorized_keys")
12
+ def initialize(member_keys = {}, attach_command)
13
+ self.member_keys = member_keys
14
+ self.attach_command = attach_command
15
+ self.key_file_path = File.expand_path("~/.ssh/authorized_keys")
15
16
  end
16
17
 
17
18
  def install
18
- return nil if self.member_keys.values.empty? || self.member_keys.values.map { |k,v| v }.empty?
19
+ return if member_keys.empty?
19
20
 
20
21
  backup_authorized_keys if key_file_exists?
21
22
  create_authorized_keys
@@ -45,10 +46,6 @@ module Pair
45
46
  FileUtils.mv(backup_key_file_path, self.key_file_path)
46
47
  end
47
48
 
48
- def line_numbers_of(key)
49
- `grep -ns ".*#{key}.*" #{self.key_file_path} | sed 's/\:.*//'`.split('\n').map(&:strip)
50
- end
51
-
52
49
  def key_file_exists?
53
50
  File.exists? self.key_file_path
54
51
  end
@@ -79,17 +76,18 @@ module Pair
79
76
  end
80
77
 
81
78
  def write_rows_for keys, of_type, in_file
79
+ read_only = of_type == 'viewer'
80
+
82
81
  keys.each do |key|
83
- in_file.puts "command=\"#{command(session, of_type)}\",#{key_options.join(',')} #{key["content"]} #id:#{key["id"]}"
84
- end
85
- in_file.puts ""
86
- end
82
+ command = attach_command[read_only].join(' ').inspect
87
83
 
88
- def command(session, type)
89
- options = ["-S /tmp/pairmill/tmux-#{session.name} attach"]
90
- options << "-r" if type == 'viewer'
84
+ options = ["command=#{command}", *key_options].join(',')
85
+ content = key["content"]
86
+ comment = "# id: #{key["id"]}"
91
87
 
92
- "/usr/local/bin/tmux #{options.join(' ')}"
88
+ in_file.puts [options, content, comment].join(' ')
89
+ end
90
+ in_file.puts ""
93
91
  end
94
92
 
95
93
  def key_options
@@ -1,8 +1,16 @@
1
1
  module Pair
2
2
  class Session
3
+ def self.host(options)
4
+ session = HostedSession.new(options)
5
+ at_exit { session.stop! }
6
+
7
+ session.start!
8
+ session.stop!
9
+ end
10
+
3
11
  class HostedSession < self
4
- attr_accessor :tunnel, :authorized_keys_file, :tmux, :response
5
- private :tunnel=, :authorized_keys_file=, :tmux=, :response=
12
+ attr_accessor :tunnel, :authorized_keys_file, :response
13
+ private :tunnel=, :authorized_keys_file=, :response=
6
14
 
7
15
  def initialize(options = {})
8
16
  puts "Hosting session #{"called #{options[:name].inspect} " if options[:name]}..."
@@ -10,7 +18,6 @@ module Pair
10
18
  self.name = options.delete(:name)
11
19
  self.viewers = options.delete(:viewers) || []
12
20
  self.participants = options.delete(:participants) || []
13
- self.tmux = Tmux.new(self)
14
21
 
15
22
  super(options)
16
23
  end
@@ -24,25 +31,48 @@ module Pair
24
31
  tmux.attach
25
32
  end
26
33
  else
27
- puts "There was a problem starting the host session %s" % (name && name.inspect)
28
- puts "response: #{response.inspect}" if response && $-d
29
- puts ""
34
+ connection_error!
30
35
  end
31
36
 
32
37
  exit
33
38
  end
34
39
 
40
+ def stop!
41
+ tmux.stop
42
+ tunnel.close
43
+ cleanup_authorized_keys
44
+ rescue
45
+ raise if $-d
46
+ end
47
+
48
+ def host_login
49
+ `whoami`.chomp
50
+ end
51
+
52
+ private
53
+
54
+ def tmux
55
+ @tmux ||= Tmux.new(name)
56
+ end
57
+
58
+ def tunnel
59
+ @tunnel ||= Tunnel.new(response["tunnel"])
60
+ end
61
+
62
+ def authorized_keys_file
63
+ @key_file ||= AuthorizedKeysFile.new(response["member_keys"], tmux.method(:attach_command))
64
+ end
65
+
35
66
  def display_startup_message
36
67
  puts "Your pairs can connect to this session using the following command:"
37
68
  puts ""
38
69
  puts " #{connect_command}"
39
70
  puts ""
40
- print "Press any key to continue..."
71
+ print "Press [Enter] to continue..."
41
72
 
42
73
  gets
43
74
  end
44
75
 
45
- # TODO: this should get host/user from response
46
76
  def connect_command
47
77
  "ssh-add; ssh -tqA -l#{bastion["join_user"]} #{bastion["host"]} #{name}"
48
78
  end
@@ -51,40 +81,31 @@ module Pair
51
81
  response["tunnel"]["bastion"]
52
82
  end
53
83
 
54
- def host_login
55
- `whoami`.chomp
56
- end
57
-
58
84
  def cleanup_authorized_keys
59
85
  authorized_keys_file.cleanup
60
86
  end
61
87
 
62
- private
63
-
64
88
  def setup
65
89
  create_session_on_server && authorized_keys_file.install
66
90
  end
67
91
 
68
92
  def create_session_on_server
69
93
  self.response = Api.create_session(self)["session"]
70
-
71
- if self.response
72
- self.name = response["name"]
73
- self.tunnel = Tunnel.new(self.response["tunnel"].merge(:host => true))
74
- self.authorized_keys_file = AuthorizedKeysFile.new(self.response["member_keys"], self)
94
+ if response
95
+ self.name = response['name']
96
+ true
97
+ else
98
+ false
75
99
  end
76
100
  end
77
101
 
78
- def stop!
79
- tunnel.close
80
- tmux.stop
81
- cleanup_authorized_keys
102
+ def connection_error!
103
+ puts "There was a problem starting the host session %s" % (name && name.inspect)
104
+ puts "response: #{response.inspect}" if response && $-d
105
+ puts ""
106
+ abort
82
107
  end
83
108
  end
84
-
85
- def self.host(options)
86
- HostedSession.new(options).start!
87
- end
88
109
  end
89
110
  end
90
111
 
@@ -1,73 +1,48 @@
1
1
  require 'fileutils'
2
+ require 'tmpdir'
2
3
 
3
4
  module Pair
4
5
  class Session
5
6
  class Tmux
6
- TMP_PATH = "/tmp"
7
+ attr_accessor :session_name
8
+ private :session_name=
7
9
 
8
- attr_accessor :session
9
- private :session=
10
-
11
- def initialize(session)
12
- self.session = session
13
- create_socket_directory
14
- end
15
-
16
- def app_path
17
- self.class.to_s.split('::').first.downcase
18
- end
19
-
20
- def unique
21
- @unique ||= srand.to_s[0,5]
10
+ def initialize(session_name)
11
+ self.session_name = session_name
22
12
  end
23
13
 
24
14
  def start
25
15
  args = %W[-S #{socket_path} new-session -d]
26
- system "tmux", *args
16
+ system tmux, *args
17
+ end
27
18
 
28
- at_exit { stop }
19
+ def attach(read_only = false)
20
+ system(*attach_command(read_only))
29
21
  end
30
22
 
31
23
  def stop
32
- `lsof -t #{socket_path}/ | xargs kill -9`
24
+ `lsof -t #{socket_path}/ 2>/dev/null | xargs kill -9`
33
25
  FileUtils.rm_f(socket_path)
34
- self.session.cleanup_authorized_keys if self.session.respond_to?(:cleanup_authorized_keys)
35
26
  end
36
27
 
37
- def window(command)
38
- args = %W[
39
- -S #{socket_path}
40
- new-window
41
- -t #{session.name}:0
42
- -n 'Pairing'
43
- 'ssh pair@bastion.pairmill.com -A'
44
- ]
45
-
46
- system "tmux", *args
47
- end
48
-
49
- def attach(read_only = false)
50
- args = %W[-S #{socket_path} attach]
51
- args += " -r" if read_only
52
-
53
- system "tmux", *args
28
+ def attach_command(read_only = false)
29
+ args = %W[#{tmux} -S #{socket_path} attach]
30
+ args << " -r" if read_only
31
+ args
54
32
  end
55
33
 
56
34
  private
57
- def create_socket_directory
58
- FileUtils.mkdir_p(socket_directory, :mode => 0700)
59
- end
60
35
 
61
- def socket_directory
62
- File.join TMP_PATH, app_path
36
+ def tmux
37
+ @tmux ||= `which tmux`.chomp
63
38
  end
64
39
 
65
40
  def socket_path
66
- File.join socket_directory, socket_name
41
+ File.join(Dir.tmpdir, socket_name)
67
42
  end
68
43
 
69
44
  def socket_name
70
- "tmux-#{session.name}"
45
+ "pair-#{session_name.gsub(/[^\w_-]+/,'')}.tmux"
71
46
  end
72
47
  end
73
48
  end
@@ -24,8 +24,11 @@ module Pair
24
24
  def open
25
25
  self.tunnel = IO.popen(ssh_command)
26
26
  puts "SSH tunnel started (PID = #{tunnel.pid})" if $-d
27
- at_exit { close }
28
- yield if block_given?
27
+
28
+ if block_given?
29
+ yield
30
+ close
31
+ end
29
32
  end
30
33
 
31
34
  def close
@@ -41,15 +44,11 @@ module Pair
41
44
 
42
45
  def ssh_command
43
46
  options = []
44
- if self.options[:host]
45
- options << "-nq"
46
- options << "-l #{bastion["host_user"]}"
47
- options << "-p #{bastion["ssh_port"]}" unless bastion["ssh_port"] == 22
48
- options << "-R #{port}:localhost:#{host_port}"
49
- else
50
- options << "-tAq"
51
- options << "-l #{bastion["join_user"]}"
52
- end
47
+
48
+ options << "-nqT" # Run no command, be quiet, don't allocate pseudo-terminal
49
+ options << "-l #{bastion["host_user"]}"
50
+ options << "-p #{bastion["ssh_port"]}" unless bastion["ssh_port"] == 22
51
+ options << "-R #{port}:localhost:#{host_port}"
53
52
 
54
53
  "ssh #{bastion["host"]} #{options.join(" ")}"
55
54
  end
@@ -1,3 +1,3 @@
1
1
  module Pair
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -2,10 +2,10 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
2
 
3
3
  require 'fileutils'
4
4
 
5
- describe Pairmill::Session::AuthorizedKeysFile do
5
+ describe Pair::Session::AuthorizedKeysFile do
6
6
  let(:member_keys) { FixtureHelper.user_keys }
7
7
  let(:session) { "testing-session" }
8
- let(:subject) { Pairmill::Session::AuthorizedKeysFile.new(member_keys, session) }
8
+ let(:subject) { Pair::Session::AuthorizedKeysFile.new(member_keys, session) }
9
9
 
10
10
  before do
11
11
  subject.stub!(:backup_authorized_keys)
@@ -1,15 +1,15 @@
1
1
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
3
4
  require 'rspec'
4
5
  require 'json'
5
6
  require 'fixture_helper'
6
- require 'pairmill'
7
- require 'pairmill/session'
7
+ require 'pair'
8
8
 
9
9
  # Requires supporting files with custom matchers and macros, etc,
10
10
  # in ./support/ and its subdirectories.
11
11
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
12
12
 
13
13
  RSpec.configure do |config|
14
-
14
+
15
15
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pair
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-11-26 00:00:00.000000000Z
13
+ date: 2011-11-27 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: httparty
17
- requirement: &70280668289560 !ruby/object:Gem::Requirement
17
+ requirement: &70298620262940 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: 0.8.1
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *70280668289560
25
+ version_requirements: *70298620262940
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rspec
28
- requirement: &70280668276060 !ruby/object:Gem::Requirement
28
+ requirement: &70298620258860 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ~>
@@ -33,7 +33,7 @@ dependencies:
33
33
  version: 2.3.0
34
34
  type: :development
35
35
  prerelease: false
36
- version_requirements: *70280668276060
36
+ version_requirements: *70298620258860
37
37
  description: Effortless remote pairing
38
38
  email:
39
39
  - me@bjeanes.com
@@ -66,9 +66,7 @@ files:
66
66
  - spec/fixtures/api_hosted_session.yml
67
67
  - spec/fixtures/api_joined_session.yml
68
68
  - spec/fixtures/user_keys.yml
69
- - spec/pairmill/session/authorized_keys_file_spec.rb
70
- - spec/pairmill/session/joined_session_spec.rb
71
- - spec/pairmill/session/session_spec.rb
69
+ - spec/pair/session/authorized_keys_file_spec.rb
72
70
  - spec/spec_helper.rb
73
71
  homepage: http://www.pairmill.com
74
72
  licenses: []
@@ -99,7 +97,5 @@ test_files:
99
97
  - spec/fixtures/api_hosted_session.yml
100
98
  - spec/fixtures/api_joined_session.yml
101
99
  - spec/fixtures/user_keys.yml
102
- - spec/pairmill/session/authorized_keys_file_spec.rb
103
- - spec/pairmill/session/joined_session_spec.rb
104
- - spec/pairmill/session/session_spec.rb
100
+ - spec/pair/session/authorized_keys_file_spec.rb
105
101
  - spec/spec_helper.rb
@@ -1,16 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
-
3
- describe Pairmill::Session::JoinedSession do
4
- let(:host) { "chad.pry@gmail.com" }
5
- let(:name) { "testing-conference" }
6
-
7
- describe "when instantiating an object" do
8
- it "sets the host" do
9
- Pairmill::Session::JoinedSession.new(host, name).host.should == host
10
- end
11
-
12
- it "sets the name" do
13
- Pairmill::Session::JoinedSession.new(host, name).name.should == name
14
- end
15
- end
16
- end
@@ -1,40 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
-
3
- describe Pairmill::Session do
4
- let(:host) { "chad.pry@gmail.com" }
5
- let(:name) { "testing-conference" }
6
-
7
- # describe "when joining a session" do
8
- # describe "the returned session" do
9
- # let(:joined_session) { Pairmill::Session::JoinedSession.new(host, name) }
10
- #
11
- # before do
12
- # Pairmill::Session::JoinedSession.stub!(:new).and_return(joined_session)
13
- # end
14
- #
15
- # it "starts a joined session" do
16
- # joined_session.should_receive(:start!)
17
- # Pairmill::Session.join(:host => host, :session_name => name)
18
- # end
19
- # end
20
- # end
21
-
22
- describe "starting a session" do
23
- let(:session_json) { FixtureHelper.api_joined_session }
24
-
25
- before do
26
- Pairmill::Api.stub!(:join_session).and_return(session_json)
27
- end
28
-
29
- it "fetches a session from the api" do
30
- session = Pairmill::Session::JoinedSession.new(host, name)
31
- session.should_receive(:fetch_session_details)
32
- session.start!
33
- end
34
-
35
- it "returns a joined session instance" do
36
- session = Pairmill::Session::JoinedSession.new(host, name)
37
- session.should be_a(Pairmill::Session::JoinedSession)
38
- end
39
- end
40
- end