tweemux 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gemspec CHANGED
@@ -7,7 +7,7 @@ Working.gemspec(
7
7
  :name => 'tweemux',
8
8
  :summary => Working.third_line_of_readme,
9
9
  #:description => Working.readme_snippet(/== Usage/, /== TODO/),
10
- :description => Working.third_line_of_readme,
10
+ :description => 'tweemux host; tweemux at some_machine; plus some more stuff',
11
11
  :version => Tweemux::VERSION,
12
12
  :authors => %w(☈king),
13
13
  :email => 'rking-tweemux@sharpsaw.org',
data/README.md CHANGED
@@ -28,7 +28,16 @@ For starters:
28
28
 
29
29
  Then, create the user on your machine (this varies. On decent Unices, it's `adduser` or `useradd`. On OS X you can either get an [adduser-like script](https://raw.github.com/sharpsaw/mac-dots/master/bin/adduser) or do it through the System Preferences GUI).
30
30
 
31
- If you're on a machine behind a firewall, you have these options:
31
+ Now, you can install the 'keyholes' for this user from Github. This means they
32
+ will be able to get in without manually typing a password, just like when they
33
+ `git push` to Github:
34
+
35
+ tweemux hubkey cirwin github: ConradIrwin
36
+ # or, if their Unix username is their Github username, there's a shorthand:
37
+ tweemux hubkey rking
38
+
39
+ Now, they'll need a route to your sshd port. If you're on a machine behind a
40
+ firewall, you have these options:
32
41
 
33
42
  * VPN. If you're on a business network with your pair, you probably can already `ping` each other's machines. Easy stuff, then.
34
43
  * Directly open a port, such as going to your router config (perhaps at http://10.0.0.1 ?) and setting it to pass the external IP (see `curl ifconfig.me` or http://whatismyip.com ) through to your local box. This is smpler once you get it set up, as long as your location is stable and you have control over the router.
@@ -52,11 +61,33 @@ It's also nice to share a windowing environment session as well. For example, th
52
61
 
53
62
  If you don't have a public SSH account (like the way I use sharpsaw.org, above), let me know ( i-am-stuck@sharpsaw.org ). We'll solve that.
54
63
 
64
+ ## Comms
65
+
66
+ Once you've shared the tmux session, you've got a lot. But you still need more bandwidth with your pair.
67
+
68
+ There are a few solutions:
69
+
70
+ - *Use inline comments* to type back and forth. Properly configured shells can also allow you to prefix with a `#` and say whatever you want. The downside is that only one person can be typing at any one time. A custom that helps is if you type what you're saying, then leave a trailing `#` with no space after it to indicate that you're done and waiting on your pair to type. This is a bit crufty, but some people are shy and only want to do the tmux share.
71
+ - *Use IRC*. If you make a tmux pane and connect it to IRC (or some other text-based chat), both local users plus that shared session can all join the same channel. This provides the person that isn't driving the keyboard to switch to their local chat window and type something for the other person to see. (TODO: build this in as a tweemux feature).
72
+ - *Use voice*. A much more powerful way to work. You "can" use Skype, but it's a commercial product and is continuously flaky. A better alternative is to sign up for a [SIP account](https://ekiga.net/), then get a [SIP client](https://en.wikipedia.org/wiki/List_of_SIP_software#Clients). For Linux, I use (Ekiga)[https://en.wikipedia.org/wiki/Ekiga), and for OS X I use [Telephone.app](http://www.tlphn.com/). Don't forget, if you can't get the Internetty stuff to work, there's always calling each other on cell phones.
73
+
55
74
  ## TODO
56
75
 
57
- tweemux keys lwoodson # when their Github username == desired Unix username
58
- # -or-
59
- tweemux keys cirwin github: ConradIrwin
76
+ # PeopleAdmin/tweemux open issues
77
+ * 18: Rogue Mode 3
78
+ * 17: Mention Google Voice/Hangouts 1
79
+ * 16: Promote regular tmux session to tweemux
80
+ * 15: Guest usage to connect to a different socket path
81
+ * 14: Add pseudo_restart of 'retry'
82
+ * 13: $TERM
83
+ * 12: Mosh possible
84
+ * 11: Basics of Tmux
85
+ * 8: Port fw without ssh [enhancement] [question]
86
+ * 7: adduser/useradd call [enhancement]
87
+ * 6: Mac setup instructions [easy-peasy] [Mac]
88
+ * 5: log [enhancement] [easy-peasy] [must-have]
89
+ * 4: brew install someurl [Mac]
90
+ * 1: --help and help [easy-peasy] [must-have]
60
91
 
61
92
  ## Thanks to
62
93
 
@@ -0,0 +1,45 @@
1
+ class Tweemux::Action::Hubkey < Tweemux::Action
2
+ attr_reader :github_user, :unix_user
3
+ def run args
4
+ @unix_user, @github_user = args
5
+ @github_user ||= @unix_user
6
+ run_with_both_usernames
7
+ end
8
+
9
+ def run_with_both_usernames
10
+ ensure_ssh_dir_exists
11
+ refuse_to_overwrite_authorized_keys_file
12
+ install_github_keys
13
+ end
14
+
15
+ def ensure_ssh_dir_exists
16
+ explained_run_as unix_user, %W(mkdir -p -m700 #{home_dir}/.ssh),
17
+ "Make sure #{unix_user} has a ~/.ssh/ dir"
18
+ end
19
+
20
+ def refuse_to_overwrite_authorized_keys_file
21
+ return unless File.exists? authorized_keys_path
22
+ # TODO: some color
23
+ raise NoRestartsException, <<-EOT
24
+ Refusing to overwrite #{authorized_keys_path}
25
+ Try: sudo cat #{authorized_keys_path}
26
+ Then maybe: sudo rm #{authorized_keys_path}
27
+ EOT
28
+ end
29
+
30
+ def install_github_keys
31
+ key_url = "https://github.com/#{github_user}.keys"
32
+ explained_run_as unix_user, %W(curl #{key_url} -o #{authorized_keys_path}),
33
+ "Download #{github_user}'s 'keyholes' from Github"
34
+ end
35
+
36
+ def home_dir
37
+ begin
38
+ their_dir = File.expand_path '~'+unix_user
39
+ rescue ArgumentError
40
+ raise NoSuchHomeDir
41
+ end
42
+ end
43
+
44
+ def authorized_keys_path; home_dir+'/.ssh/authorized_keys' end
45
+ end
@@ -9,12 +9,21 @@ class Tweemux
9
9
  end
10
10
 
11
11
  class FunkyUsage < RuntimeError; end
12
+ class NoSuchHomeDir < RuntimeError; end
13
+ class NoRestartsException < RuntimeError; end
12
14
 
13
15
  def run args; raise 'Unimplemented' end
14
16
 
15
- # Hrm. This is kinda gross, but I feel like it cleans up the subclasses
16
- def explained_run *a; self.class.explained_run *a end
17
- def tmux_S *a; self.class.tmux_S *a end
17
+ # Hrm. These are kinda gross, but I feel like it cleans up the subclasses
18
+ def explained_run what, why
19
+ self.class.explained_run what, why
20
+ end
21
+ def explained_run_as who, what, why
22
+ self.class.explained_run_as who, what, why
23
+ end
24
+ def tmux_S *a
25
+ self.class.tmux_S *a
26
+ end
18
27
 
19
28
  class DubiousSystemInvocation < RuntimeError; end
20
29
  class << self
@@ -30,6 +39,11 @@ class Tweemux
30
39
  system_or_raise what
31
40
  end
32
41
 
42
+ def explained_run_as user, what, why
43
+ full_command = ['sudo', '-u', user] + what
44
+ explained_run full_command, why
45
+ end
46
+
33
47
  def explain what, why
34
48
  warn highlight_command(what) + highlight_explanation(why)
35
49
  end
@@ -81,6 +95,8 @@ To run anyway, hit: #{enter}
81
95
  require 'pry'
82
96
  binding.pry
83
97
  end
98
+ rescue Interrupt
99
+ exit 2
84
100
  end
85
101
 
86
102
  def load_all!
@@ -1,3 +1,3 @@
1
1
  class Tweemux
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/tweemux.rb CHANGED
@@ -8,6 +8,9 @@ class Tweemux
8
8
  def run args
9
9
  action = understand args
10
10
  action.call
11
+ rescue Tweemux::Action::NoRestartsException => e
12
+ warn e.message.color :error
13
+ exit 1
11
14
  end
12
15
 
13
16
  def understand args
@@ -2,12 +2,17 @@ require_relative 'test_helper'
2
2
 
3
3
  module TweemuxActionHelper
4
4
  def test_run
5
+ assert_equal stubbed_run.to_yaml, expected_commands.to_yaml
6
+ end
7
+
8
+ def stubbed_run
5
9
  explained_runs = []
6
- Tweemux::Action.stub :explained_run, -> *a { explained_runs << a } do
10
+ Tweemux::Action.stub :explained_run, -> what, why {
11
+ explained_runs << [ what, why ]
12
+ } do
7
13
  Tweemux.run argv
8
14
  end
9
- got = explained_runs.map &:first
10
- assert_equal got.to_yaml, expected_commands.to_yaml
15
+ explained_runs.map &:first # drop the explanations
11
16
  end
12
17
 
13
18
  def bad_runs; [] end
@@ -0,0 +1,64 @@
1
+ require_relative '../../action_test_helper'
2
+ require 'ostruct'
3
+
4
+ class Tweemux::Action::HubkeyTest < MiniTest::Unit::TestCase
5
+ include TweemuxActionHelper
6
+ def argv; %w(bro hi HiOnGithub) end
7
+ def test_run
8
+ commands_run = nil
9
+ with_fake_expand_path expecting: '~hi', expanding_to: '/home/hi' do
10
+ commands_run = stubbed_run
11
+ end
12
+ assert_equal %w(sudo -u hi mkdir -p -m700 /home/hi/.ssh),
13
+ commands_run.shift
14
+ assert_equal %W(
15
+ sudo -u hi
16
+ curl https://github.com/HiOnGithub.keys
17
+ -o /home/hi/.ssh/authorized_keys),
18
+ commands_run.shift
19
+ assert commands_run.empty?, commands_run
20
+ end
21
+
22
+ def test_run_will_not_clobber_auth_keys_file
23
+ with_fake_expand_path expecting: '~hi', expanding_to: '/home/hi' do
24
+ File.stub :exists?, -> path {
25
+ assert_equal '/home/hi/.ssh/authorized_keys', path
26
+ true
27
+ } do
28
+ stubbed_run
29
+ end
30
+ end
31
+ fail "Shouldn't get here"
32
+ rescue Tweemux::Action::NoRestartsException => e
33
+ assert_match /refusing to overwrite.*authorized_keys/i, e.message
34
+ end
35
+
36
+ def with_fake_expand_path args
37
+ File.stub :expand_path, -> short_path {
38
+ assert_equal args[:expecting], short_path
39
+ args[:expanding_to]
40
+ } do yield end
41
+ end
42
+
43
+ def test_no_homedir
44
+ File.stub :expand_path, -> path { raise ArgumentError, 'no such user' } do
45
+ stubbed_run
46
+ end
47
+ rescue Tweemux::Action::NoSuchHomeDir
48
+ else
49
+ fail 'Should be noisy about missing users'
50
+ end
51
+
52
+ def test_shorthand_invocation
53
+ action = Tweemux::Action::Hubkey.new :unused
54
+ called = false
55
+ action.stub :run_with_both_usernames, -> {
56
+ called = true
57
+ } do
58
+ action.run 'a'
59
+ end
60
+ assert called
61
+ assert_equal 'a', action.unix_user
62
+ assert_equal 'a', action.github_user
63
+ end
64
+ end
data/test/tweemux_test.rb CHANGED
@@ -16,14 +16,19 @@ class TweemuxTest < MiniTest::Unit::TestCase
16
16
  end
17
17
 
18
18
  def test_ruby18
19
- return warn "Needs a working ruby18 executable in $PATH".color(:orange) \
20
- unless ruby18ok 'test/ok18.rb'
21
- # TODO: optimize this by running them all in one command
22
- Dir['{bin,lib}/*.rb'].each do |e|
23
- fail "ruby18 hates #{e}" unless "Syntax OK\n" == `ruby18 -c #{e}`
24
- end
19
+ got = `ruby18 -Ilib -rtweemux -e1`
20
+ fail "ruby18 hates us: #{got}" unless got.empty?
25
21
  rescue Errno::ENOENT => e
26
- skip 'Needs ruby18 executable in $PATH' if e.message[/ruby18/]
22
+ # TODO: colorize
23
+ skip <<-EOT if e.message[/ruby18/]
24
+ This test needs a 'ruby18' executable in $PATH
25
+ If using rbenv, one such script might be:
26
+
27
+ #!/bin/sh -e
28
+ eval "$(rbenv init -)"
29
+ rbenv shell 1.8.7-p371
30
+ ruby "$@"
31
+ EOT
27
32
  raise e
28
33
  end
29
34
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tweemux
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,16 +9,13 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-28 00:00:00.000000000 Z
12
+ date: 2013-03-05 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'For Remote Pair Programming: A handy script to create-or-join a world-readable
15
15
  tmux session
16
16
 
17
17
 
18
- For Remote Pair Programming: A handy script to create-or-join a world-readable tmux
19
- session
20
-
21
- '
18
+ tweemux host; tweemux at some_machine; plus some more stuff'
22
19
  email: rking-tweemux@sharpsaw.org
23
20
  executables:
24
21
  - tweemux
@@ -40,7 +37,7 @@ files:
40
37
  - lib/tweemux/action/at.rb
41
38
  - lib/tweemux/action/forward.rb
42
39
  - lib/tweemux/action/host.rb
43
- - lib/tweemux/action/keys.rb
40
+ - lib/tweemux/action/hubkey.rb
44
41
  - lib/tweemux/action/share.rb
45
42
  - lib/tweemux/core_ext.rb
46
43
  - lib/tweemux/version.rb
@@ -50,6 +47,7 @@ files:
50
47
  - test/tweemux/action/at_test.rb
51
48
  - test/tweemux/action/forward_test.rb
52
49
  - test/tweemux/action/host_test.rb
50
+ - test/tweemux/action/hubkey_test.rb
53
51
  - test/tweemux/action/share_test.rb
54
52
  - test/tweemux/action_test.rb
55
53
  - test/tweemux_test.rb
@@ -60,17 +58,17 @@ rdoc_options: []
60
58
  require_paths:
61
59
  - lib
62
60
  required_ruby_version: !ruby/object:Gem::Requirement
63
- none: false
64
61
  requirements:
65
62
  - - ! '>='
66
63
  - !ruby/object:Gem::Version
67
64
  version: '0'
68
- required_rubygems_version: !ruby/object:Gem::Requirement
69
65
  none: false
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
67
  requirements:
71
68
  - - ! '>='
72
69
  - !ruby/object:Gem::Version
73
70
  version: '0'
71
+ none: false
74
72
  requirements: []
75
73
  rubyforge_project:
76
74
  rubygems_version: 1.8.23
@@ -85,6 +83,7 @@ test_files:
85
83
  - test/tweemux/action/at_test.rb
86
84
  - test/tweemux/action/forward_test.rb
87
85
  - test/tweemux/action/host_test.rb
86
+ - test/tweemux/action/hubkey_test.rb
88
87
  - test/tweemux/action/share_test.rb
89
88
  - test/tweemux/action_test.rb
90
89
  - test/tweemux_test.rb
@@ -1,3 +0,0 @@
1
- class Tweemux::Action::Keys < Tweemux::Action
2
-
3
- end