i2c2 1.0.0.beta4 → 1.0.0.beta5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -1
- data/Gemfile +1 -4
- data/Gemfile.lock +33 -38
- data/README.md +7 -18
- data/Rakefile +4 -3
- data/VERSION +1 -1
- data/bin/i2c2 +196 -232
- data/i2c2.gemspec +7 -17
- data/lib/i2c2.rb +144 -144
- metadata +8 -50
- data/.document +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e5df5c0abdd9207ac837daa324f76e909c75d68d910e38a41cd74b8a5b9f831
|
4
|
+
data.tar.gz: 44ccc3cc3b3352b202803afe055af829e9a377b7f96781910463f06e76ccffe5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26e238fc897f8319bcafceda6ea485720c798c1e8a504e216abe2900375a8420f64918d4a366e9aac38ff6626497116b971e27cd6d2be5bd00e9b6177921432d
|
7
|
+
data.tar.gz: afefcd2de29436d6d180e406ed06ddf952f7fdcbc3ba2f76ca6357ae89258b83fc2b48c70454785123559e3e91346f95bcec673d583b34e5376eb2ecb7f6282d
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
+
## [1.0.0.beta5] 2020-09-10
|
6
|
+
### Changed
|
7
|
+
- Remove support for connecting to cluster/hosts without using the explicit option
|
8
|
+
- Change default direction from column to row
|
9
|
+
|
5
10
|
## [1.0.0.beta4] 2019-05-15
|
6
11
|
### Changed
|
7
12
|
- Fix problem after config file convertion to version 2
|
@@ -22,4 +27,4 @@
|
|
22
27
|
- 100% compatible with i2cssh *branch master* at the time of fork (commit: ac0bf90), including auto complete config file name i2cssh-autocomplete.bash
|
23
28
|
|
24
29
|
## [0.99.0] - 2019-05-11
|
25
|
-
- 100% compatible with i2cssh *2.2.0 (latest
|
30
|
+
- 100% compatible with i2cssh *2.2.0 (latest release)*, including the config file ~/.i2csshrc
|
data/Gemfile
CHANGED
@@ -8,8 +8,5 @@ gem "rb-scpt", "~> 1.0.1"
|
|
8
8
|
# Add dependencies to develop your gem here.
|
9
9
|
# Include everything needed to run rake, tests, features, etc.
|
10
10
|
group :development do
|
11
|
-
gem "
|
12
|
-
gem "jeweler", "2.1.2"
|
13
|
-
gem "shoulda"
|
14
|
-
gem "builder"
|
11
|
+
gem "jeweler"
|
15
12
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,65 +1,60 @@
|
|
1
1
|
GEM
|
2
2
|
remote: https://rubygems.org/
|
3
3
|
specs:
|
4
|
-
addressable (2.
|
5
|
-
|
6
|
-
builder (3.2.2)
|
4
|
+
addressable (2.4.0)
|
5
|
+
builder (3.2.4)
|
7
6
|
descendants_tracker (0.0.4)
|
8
7
|
thread_safe (~> 0.3, >= 0.3.1)
|
9
8
|
faraday (0.9.2)
|
10
9
|
multipart-post (>= 1.2, < 3)
|
11
|
-
git (1.
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
git (1.7.0)
|
11
|
+
rchardet (~> 1.8)
|
12
|
+
github_api (0.16.0)
|
13
|
+
addressable (~> 2.4.0)
|
14
|
+
descendants_tracker (~> 0.0.4)
|
15
15
|
faraday (~> 0.8, < 0.10)
|
16
|
-
hashie (>=
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
jeweler (2.1.2)
|
16
|
+
hashie (>= 3.4)
|
17
|
+
mime-types (>= 1.16, < 3.0)
|
18
|
+
oauth2 (~> 1.0)
|
19
|
+
hashie (4.1.0)
|
20
|
+
highline (2.0.3)
|
21
|
+
jeweler (2.3.9)
|
23
22
|
builder
|
24
|
-
bundler
|
23
|
+
bundler
|
25
24
|
git (>= 1.2.5)
|
26
|
-
github_api (~> 0.
|
25
|
+
github_api (~> 0.16.0)
|
27
26
|
highline (>= 1.6.15)
|
28
27
|
nokogiri (>= 1.5.10)
|
28
|
+
psych
|
29
29
|
rake
|
30
30
|
rdoc
|
31
|
-
|
32
|
-
jwt (
|
33
|
-
|
34
|
-
|
31
|
+
semver2
|
32
|
+
jwt (2.2.2)
|
33
|
+
mime-types (2.99.3)
|
34
|
+
mini_portile2 (2.4.0)
|
35
|
+
multi_json (1.15.0)
|
35
36
|
multi_xml (0.6.0)
|
36
|
-
multipart-post (2.1.
|
37
|
-
nokogiri (1.
|
38
|
-
mini_portile2 (~> 2.
|
39
|
-
oauth2 (1.4.
|
40
|
-
faraday (>= 0.8, <
|
37
|
+
multipart-post (2.1.1)
|
38
|
+
nokogiri (1.10.10)
|
39
|
+
mini_portile2 (~> 2.4.0)
|
40
|
+
oauth2 (1.4.4)
|
41
|
+
faraday (>= 0.8, < 2.0)
|
41
42
|
jwt (>= 1.0, < 3.0)
|
42
43
|
multi_json (~> 1.3)
|
43
44
|
multi_xml (~> 0.5)
|
44
45
|
rack (>= 1.2, < 3)
|
45
|
-
|
46
|
-
rack (
|
47
|
-
rake (
|
46
|
+
psych (3.2.0)
|
47
|
+
rack (2.2.3)
|
48
|
+
rake (13.0.1)
|
48
49
|
rb-scpt (1.0.3)
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
rchardet (1.8.0)
|
51
|
+
rdoc (6.2.1)
|
52
|
+
semver2 (3.4.2)
|
52
53
|
thread_safe (0.3.6)
|
53
54
|
|
54
55
|
PLATFORMS
|
55
56
|
ruby
|
56
57
|
|
57
58
|
DEPENDENCIES
|
58
|
-
|
59
|
-
bundler (>= 1.0.0)
|
60
|
-
jeweler (= 2.1.2)
|
59
|
+
jeweler
|
61
60
|
rb-scpt (~> 1.0.1)
|
62
|
-
shoulda
|
63
|
-
|
64
|
-
BUNDLED WITH
|
65
|
-
1.17.3
|
data/README.md
CHANGED
@@ -18,7 +18,7 @@ When using iTerm2 < 2.9, install old i2cssh version 1.16.0:
|
|
18
18
|
|
19
19
|
## Migrate from i2cssh
|
20
20
|
|
21
|
-
If you have used i2cssh and want to migrate, you can do it painless using i2c2 version 0.99.0 which is 100% compatible with i2cssh 2.2.0 (latest
|
21
|
+
If you have used i2cssh and want to migrate, you can do it painless using i2c2 version 0.99.0 which is 100% compatible with i2cssh 2.2.0 (latest release),
|
22
22
|
including the config file ~/.i2csshrc.
|
23
23
|
|
24
24
|
Version 0.99.1 is compatible with i2cssh branch master at the time of fork (commit: ac0bf90), including auto complete config file name i2cssh-autocomplete.bash.
|
@@ -46,19 +46,8 @@ Version 0.99.1 is compatible with i2cssh branch master at the time of fork (comm
|
|
46
46
|
-d, --direction DIRECTION Direction that new sessions are created (default: column)
|
47
47
|
-X, --extra EXTRA_PARAM Additional ssh parameters (e.g. -Xi=myidentity.pem)
|
48
48
|
|
49
|
-
i2c2 will assume you want to connect to a cluster when only one host is given.
|
50
|
-
|
51
49
|
For `-c` and `-m` options, the format `username@cluster` or `username@host` can be used.
|
52
50
|
|
53
|
-
The following commands are exactly the same, however, they might serve different purposes:
|
54
|
-
|
55
|
-
$ i2c2 -m user1@host1,user2@host2
|
56
|
-
$ i2c2 user1@host1 user2@host2
|
57
|
-
|
58
|
-
You can combine these options and use them multiple times:
|
59
|
-
|
60
|
-
$ i2c2 -m user1@host1,user2@host2 -m user3@host3 user4@host4 user5@host5
|
61
|
-
|
62
51
|
Using the `-l` option will override all usernames:
|
63
52
|
|
64
53
|
$ i2c2 -l foo user1@host1 user2@host2
|
@@ -79,12 +68,6 @@ The `i2csshrc` file is a YAML formatted file that contains the following structu
|
|
79
68
|
- host1
|
80
69
|
- host2
|
81
70
|
|
82
|
-
## Autocomplete
|
83
|
-
|
84
|
-
To allow autocomplete, add the following to your .bash_profile, .bashrc or .profile
|
85
|
-
|
86
|
-
$ source [path to ./extras/i2cssh-autocomplete.bash]
|
87
|
-
|
88
71
|
## Optional Parameters
|
89
72
|
|
90
73
|
They can be used globally or per cluster and include:
|
@@ -113,6 +96,12 @@ The following precedence is used:
|
|
113
96
|
|
114
97
|
Make sure the config file is valid YAML (e.g. use spaces instead of tabs)
|
115
98
|
|
99
|
+
## Autocomplete
|
100
|
+
|
101
|
+
To allow autocomplete, add the following to your .bash_profile, .bashrc or .profile
|
102
|
+
|
103
|
+
$ source [path to ./extras/i2cssh-autocomplete.bash]
|
104
|
+
|
116
105
|
## Options
|
117
106
|
|
118
107
|
### -A, --forward-agent
|
data/Rakefile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
2
|
require 'rubygems'
|
4
3
|
require 'bundler'
|
4
|
+
|
5
5
|
begin
|
6
6
|
Bundler.setup(:default, :development)
|
7
7
|
rescue Bundler::BundlerError => e
|
@@ -9,13 +9,14 @@ rescue Bundler::BundlerError => e
|
|
9
9
|
$stderr.puts "Run `bundle install` to install missing gems"
|
10
10
|
exit e.status_code
|
11
11
|
end
|
12
|
-
require 'rake'
|
13
12
|
|
13
|
+
require 'rake'
|
14
14
|
require 'jeweler'
|
15
|
+
|
15
16
|
Jeweler::Tasks.new do |gem|
|
16
17
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
18
|
gem.name = "i2c2"
|
18
|
-
gem.homepage = "
|
19
|
+
gem.homepage = "https://github.com/dx7/i2c2"
|
19
20
|
gem.license = "MIT"
|
20
21
|
gem.summary = %Q{csshX like - cluster ssh using iTerm2 panes - based on i2cssh}
|
21
22
|
gem.description = %Q{csshX like - cluster ssh using iTerm2 panes - based on i2cssh}
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.0.
|
1
|
+
1.0.0.beta5
|
data/bin/i2c2
CHANGED
@@ -4,81 +4,66 @@ require 'optparse'
|
|
4
4
|
require_relative '../lib/i2c2'
|
5
5
|
require 'yaml'
|
6
6
|
|
7
|
-
@config_file = File.expand_path
|
8
|
-
|
7
|
+
@config_file = File.expand_path '~/.i2csshrc'
|
9
8
|
@i2_options, ssh_options, @servers, @clusters, @ssh_environment, opts_from_cmdline = [], [], [], {}, [], {}
|
10
9
|
|
11
|
-
def debug_vars
|
12
|
-
p '-----------------------------'
|
13
|
-
p '@i2_options'
|
14
|
-
p @i2_options
|
15
|
-
p '@servers'
|
16
|
-
p @servers
|
17
|
-
p '@clusters'
|
18
|
-
p @clusters
|
19
|
-
p '@ssh_environment'
|
20
|
-
p @ssh_environment
|
21
|
-
p '-----------------------------'
|
22
|
-
end
|
23
|
-
|
24
10
|
def get_hosts(c)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
cluster = @clusters[clus]
|
33
|
-
if cluster
|
34
|
-
set_options(cluster, login_from_cli)
|
35
|
-
|
36
|
-
if @i2_options.last[:login]
|
37
|
-
@servers << cluster["hosts"].map{|h| "#{@i2_options.last[:login]}@#{h}"}
|
38
|
-
else
|
39
|
-
@servers << cluster["hosts"]
|
40
|
-
end
|
41
|
-
else
|
42
|
-
puts "ERROR: unknown cluster #{c}. Check your #{@config_file}"
|
43
|
-
exit 1
|
44
|
-
end
|
11
|
+
c.each do |clus|
|
12
|
+
|
13
|
+
if clus =~ /(.+)@(.+)/
|
14
|
+
login_from_cli = $1
|
15
|
+
clus = $2
|
45
16
|
end
|
46
17
|
|
18
|
+
cluster = @clusters[clus]
|
19
|
+
if cluster
|
20
|
+
set_options(cluster, login_from_cli)
|
21
|
+
|
22
|
+
if @i2_options.last[:login]
|
23
|
+
@servers << cluster['hosts'].map{|h| "#{@i2_options.last[:login]}@#{h}"}
|
24
|
+
else
|
25
|
+
@servers << cluster['hosts']
|
26
|
+
end
|
27
|
+
else
|
28
|
+
puts "ERROR: unknown cluster #{c}. Check your #{@config_file}"
|
29
|
+
exit 1
|
30
|
+
end
|
31
|
+
end
|
47
32
|
end
|
48
33
|
|
49
34
|
def set_options(config_hash, login_override=nil)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
35
|
+
if config_hash['columns'] and config_hash['rows']
|
36
|
+
puts 'CONFIG ERROR: rows and columns can\'t be used at the same time'
|
37
|
+
exit 1
|
38
|
+
end
|
54
39
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
40
|
+
if @i2_options.size == 0
|
41
|
+
@i2_options << {}
|
42
|
+
else
|
43
|
+
# The first member includes the default options from the conf file
|
44
|
+
@i2_options << @i2_options.first.clone
|
45
|
+
end
|
61
46
|
|
62
|
-
|
63
|
-
|
64
|
-
|
47
|
+
[:broadcast, :profile, :rank, :iterm2, :login, :columns, :rows, :sleep, :shell, :direction, :itermname].each do |p|
|
48
|
+
@i2_options.last[p] = config_hash[p.to_s].nil? ? @i2_options.last[p] : config_hash[p.to_s]
|
49
|
+
end
|
65
50
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
else
|
73
|
-
# We have some global env so copy it
|
74
|
-
@ssh_environment << @ssh_environment.first.clone
|
75
|
-
end
|
76
|
-
|
77
|
-
@ssh_environment.last.merge!(config_hash["environment"].inject({}){|m, v| m.merge(v)})
|
51
|
+
@i2_options.last[:login] = login_override if login_override
|
52
|
+
@i2_options.last[:direction] ||= :row
|
53
|
+
@i2_options.last[:direction] = @i2_options.last[:direction].to_sym
|
54
|
+
if config_hash['environment']
|
55
|
+
if @ssh_environment.empty?
|
56
|
+
@ssh_environment << {}
|
78
57
|
else
|
79
|
-
|
58
|
+
# We have some global env so copy it
|
59
|
+
@ssh_environment << @ssh_environment.first.clone
|
80
60
|
end
|
81
61
|
|
62
|
+
@ssh_environment.last.merge!(config_hash['environment'].inject({}){|m, v| m.merge(v)})
|
63
|
+
else
|
64
|
+
@ssh_environment << {}
|
65
|
+
end
|
66
|
+
|
82
67
|
end
|
83
68
|
|
84
69
|
if File.exists?(@config_file)
|
@@ -91,224 +76,203 @@ if File.exists?(@config_file)
|
|
91
76
|
|
92
77
|
# Read config and set defaults from config
|
93
78
|
set_options(config_hash)
|
94
|
-
@clusters = config_hash[
|
79
|
+
@clusters = config_hash['clusters']
|
95
80
|
else
|
96
81
|
set_options({})
|
97
82
|
end
|
98
83
|
|
99
|
-
|
100
84
|
optparse = OptionParser.new do |opts|
|
101
|
-
|
102
|
-
|
103
|
-
# Check if we have a cluster.
|
104
|
-
opts.on '-c', '--clusters clus1,clus2', Array,
|
105
|
-
'Comma-separated list of clusters specified in ~/.i2csshrc' do |c|
|
106
|
-
get_hosts(c)
|
107
|
-
end
|
85
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [options] [(username@host [username@host] | username@cluster)]"
|
108
86
|
|
87
|
+
# Check if we have a cluster.
|
88
|
+
opts.on '-c', '--clusters clus1,clus2', Array,
|
89
|
+
'Comma-separated list of clusters specified in ~/.i2csshrc' do |c|
|
90
|
+
get_hosts(c)
|
91
|
+
end
|
109
92
|
|
110
|
-
|
111
|
-
|
93
|
+
opts.on '-m', '--machines a,b,c', Array,
|
94
|
+
'Comma-separated list of hosts' do |h|
|
112
95
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
96
|
+
# Add to servers array and get a clone of default options
|
97
|
+
@servers << h
|
98
|
+
@i2_options << @i2_options.first.clone
|
99
|
+
if @ssh_environment.empty?
|
100
|
+
@ssh_environment << {}
|
101
|
+
else
|
102
|
+
@ssh_environment << @ssh_environment.first.clone
|
121
103
|
end
|
104
|
+
end
|
122
105
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
@ssh_environment << @ssh_environment.first.clone
|
132
|
-
end
|
106
|
+
opts.on '-f', '--file FILE',
|
107
|
+
'Cluster file (one hostname per line)' do |f|
|
108
|
+
@servers << File.read(f).split("\n")
|
109
|
+
@i2_options << @i2_options.first.clone
|
110
|
+
if @ssh_environment.empty?
|
111
|
+
@ssh_environment << {}
|
112
|
+
else
|
113
|
+
@ssh_environment << @ssh_environment.first.clone
|
133
114
|
end
|
115
|
+
end
|
134
116
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
end
|
117
|
+
opts.on '-t', '--tab-split',
|
118
|
+
'Split servers/clusters into tabs (group arguments)' do
|
119
|
+
opts_from_cmdline[:tabs] = true
|
139
120
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
opts_from_cmdline[:tabs_nogroup] = true
|
144
|
-
end
|
121
|
+
puts 'Disabling broadcast for tab split mode...'
|
122
|
+
opts_from_cmdline[:broadcast] = false
|
123
|
+
end
|
145
124
|
|
146
|
-
|
125
|
+
opts.on '-T', '--tab-split-nogroup',
|
126
|
+
'Split servers/clusters into tabs (don\'t group arguments)' do
|
127
|
+
opts_from_cmdline[:tabs] = true
|
128
|
+
opts_from_cmdline[:tabs_nogroup] = true
|
147
129
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
ssh_options << '-A'
|
152
|
-
end
|
130
|
+
puts 'Disabling broadcast for tab split mode...'
|
131
|
+
opts_from_cmdline[:broadcast] = false
|
132
|
+
end
|
153
133
|
|
154
|
-
|
155
|
-
'SSH login name' do |u|
|
156
|
-
opts_from_cmdline[:login] = u
|
134
|
+
# Command line options override config file
|
157
135
|
|
158
|
-
|
136
|
+
# SSH options
|
137
|
+
opts.on '-A', '--forward-agent',
|
138
|
+
'Enable SSH agent forwarding' do
|
139
|
+
ssh_options << '-A'
|
140
|
+
end
|
159
141
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
end
|
142
|
+
opts.on '-l', '--login LOGIN',
|
143
|
+
'SSH login name' do |u|
|
144
|
+
opts_from_cmdline[:login] = u
|
145
|
+
end
|
165
146
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
147
|
+
opts.on '-e', '--environment KEY=VAL',
|
148
|
+
'Send environment vars (comma-separated list, need to start with LC_)' do |e|
|
149
|
+
#Overwrite global ssh environment from config file
|
150
|
+
@ssh_environment[0] = e.split(',').inject({}) {|m, x| key, val = x.split('='); m[key] = val; m}
|
151
|
+
end
|
170
152
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
end
|
153
|
+
opts.on '-r', '--rank',
|
154
|
+
'Send LC_RANK with the host number as environment variable' do
|
155
|
+
opts_from_cmdline[:rank] = true
|
156
|
+
end
|
176
157
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
exit 1
|
183
|
-
else
|
184
|
-
opts_from_cmdline[:columns] = c
|
185
|
-
end
|
186
|
-
end
|
187
|
-
opts.on '-R', '--rows ROWS', Integer,
|
188
|
-
'Number of rows (columns will be calculated)' do |r|
|
189
|
-
if opts_from_cmdline[:columns]
|
190
|
-
puts "ERROR: -C and -R can't be used at the same time"
|
191
|
-
puts optparse.help
|
192
|
-
exit 1
|
193
|
-
else
|
194
|
-
opts_from_cmdline[:rows] = r
|
195
|
-
end
|
196
|
-
end
|
197
|
-
opts.on '-b', '--broadcast',
|
198
|
-
'Start with broadcast input (DANGEROUS!)' do
|
199
|
-
opts_from_cmdline[:broadcast] = true
|
200
|
-
end
|
201
|
-
opts.on '-nb', '--nobroadcast',
|
202
|
-
'Disable broadcast' do
|
203
|
-
opts_from_cmdline[:broadcast] = false
|
204
|
-
end
|
205
|
-
opts.on '-p', '--profile PROFILE',
|
206
|
-
'Name of the iTerm2 profile (default: Default)' do |p|
|
207
|
-
opts_from_cmdline[:profile] = p
|
208
|
-
end
|
209
|
-
opts.on "-2", '--iterm2',
|
210
|
-
'Use iTerm2 instead of iTerm' do
|
211
|
-
opts_from_cmdline[:iterm2] = true
|
212
|
-
end
|
213
|
-
opts.on "-i", '--itermname NAME', String,
|
214
|
-
'Name of the application to use (default: iTerm)' do |i|
|
215
|
-
opts_from_cmdline[:itermname] = i
|
216
|
-
end
|
217
|
-
opts.on '-s', '--sleep SLEEP', Float,
|
218
|
-
'Number of seconds to sleep between creating SSH sessions' do |s|
|
219
|
-
opts_from_cmdline[:sleep] = s
|
220
|
-
end
|
221
|
-
opts.on '-S', '--shell SHELL', String,
|
222
|
-
'Shell to use when spawning the SSH sessions' do |s|
|
223
|
-
opts_from_cmdline[:shell] = s
|
224
|
-
end
|
225
|
-
opts.on "-d", '--direction DIRECTION', String,
|
226
|
-
'Direction that new sessions are created (default: column)' do |d|
|
227
|
-
unless ["row", "column"].include?(d)
|
228
|
-
puts "ERROR: -d requires 'row' or 'column'"
|
229
|
-
puts optparse.help
|
230
|
-
exit 1
|
231
|
-
end
|
232
|
-
opts_from_cmdline[:direction] = d.to_sym
|
233
|
-
end
|
234
|
-
opts.on '-X', '--extra EXTRA_PARAM', String,
|
235
|
-
'Additional ssh parameters (e.g. -Xi=myidentity.pem)' do |x|
|
158
|
+
# iTerm2 options
|
159
|
+
opts.on '-F', '--fullscreen',
|
160
|
+
'Make the window fullscreen' do
|
161
|
+
opts_from_cmdline[:fullscreen] = true
|
162
|
+
end
|
236
163
|
|
237
|
-
|
164
|
+
opts.on '-C', '--columns COLUMNS', Integer,
|
165
|
+
'Number of columns (rows will be calculated)' do |c|
|
166
|
+
if opts_from_cmdline[:rows]
|
167
|
+
puts 'ERROR: -C and -R can\'t be used at the same time'
|
168
|
+
puts optparse.help
|
169
|
+
exit 1
|
170
|
+
else
|
171
|
+
opts_from_cmdline[:columns] = c
|
238
172
|
end
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
173
|
+
end
|
174
|
+
|
175
|
+
opts.on '-R', '--rows ROWS', Integer,
|
176
|
+
'Number of rows (columns will be calculated)' do |r|
|
177
|
+
if opts_from_cmdline[:columns]
|
178
|
+
puts 'ERROR: -C and -R can\'t be used at the same time'
|
179
|
+
puts optparse.help
|
180
|
+
exit 1
|
181
|
+
else
|
182
|
+
opts_from_cmdline[:rows] = r
|
243
183
|
end
|
244
|
-
end
|
245
|
-
optparse.parse!
|
184
|
+
end
|
246
185
|
|
247
|
-
|
248
|
-
|
186
|
+
opts.on '-b', '--broadcast',
|
187
|
+
'Start with broadcast input (DANGEROUS!)' do
|
188
|
+
opts_from_cmdline[:broadcast] = true
|
189
|
+
end
|
190
|
+
|
191
|
+
opts.on '-nb', '--nobroadcast',
|
192
|
+
'Disable broadcast' do
|
249
193
|
opts_from_cmdline[:broadcast] = false
|
250
|
-
end
|
194
|
+
end
|
251
195
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
196
|
+
opts.on '-p', '--profile PROFILE',
|
197
|
+
'Name of the iTerm2 profile (default: Default)' do |p|
|
198
|
+
opts_from_cmdline[:profile] = p
|
199
|
+
end
|
256
200
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
201
|
+
opts.on '-2', '--iterm2',
|
202
|
+
'Use iTerm2 instead of iTerm' do
|
203
|
+
opts_from_cmdline[:iterm2] = true
|
204
|
+
end
|
205
|
+
|
206
|
+
opts.on '-i', '--itermname NAME', String,
|
207
|
+
'Name of the application to use (default: iTerm)' do |i|
|
208
|
+
opts_from_cmdline[:itermname] = i
|
209
|
+
end
|
210
|
+
|
211
|
+
opts.on '-s', '--sleep SLEEP', Float,
|
212
|
+
'Number of seconds to sleep between creating SSH sessions' do |s|
|
213
|
+
opts_from_cmdline[:sleep] = s
|
214
|
+
end
|
215
|
+
|
216
|
+
opts.on '-S', '--shell SHELL', String,
|
217
|
+
'Shell to use when spawning the SSH sessions' do |s|
|
218
|
+
opts_from_cmdline[:shell] = s
|
219
|
+
end
|
220
|
+
|
221
|
+
opts.on '-d', '--direction DIRECTION', String,
|
222
|
+
'Direction that new sessions are created (default: row)' do |d|
|
223
|
+
unless ['row', 'column'].include?(d)
|
224
|
+
puts 'ERROR: -d requires \'row\' or \'column\''
|
225
|
+
puts optparse.help
|
226
|
+
exit 1
|
279
227
|
end
|
228
|
+
opts_from_cmdline[:direction] = d.to_sym
|
229
|
+
end
|
230
|
+
|
231
|
+
opts.on '-X', '--extra EXTRA_PARAM', String,
|
232
|
+
'Additional ssh parameters (e.g. -Xi=myidentity.pem)' do |x|
|
233
|
+
|
234
|
+
ssh_options << '-' + x.split('=').join(' ')
|
235
|
+
end
|
236
|
+
|
237
|
+
opts.on '-g', '--gateway HOST', String,
|
238
|
+
'Multihop SSH connection gateway string (e.g. username@gateway) - usually used with -A' do |g|
|
239
|
+
# ssh_gateway = g
|
240
|
+
opts_from_cmdline[:gateway] = g
|
241
|
+
end
|
280
242
|
end
|
281
243
|
|
244
|
+
optparse.parse!
|
245
|
+
|
282
246
|
# Drop default options
|
283
247
|
if @i2_options.size > @servers.size
|
284
|
-
|
248
|
+
@i2_options.shift
|
285
249
|
end
|
286
250
|
|
287
251
|
if @ssh_environment.size > @servers.size
|
288
|
-
|
252
|
+
@ssh_environment.shift
|
289
253
|
end
|
290
254
|
|
291
255
|
|
292
256
|
@i2_options.each do |opt|
|
293
|
-
|
257
|
+
opt.merge!(opts_from_cmdline)
|
294
258
|
end
|
295
259
|
|
296
260
|
@i2_options.each_with_index do |opt, i|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
261
|
+
if opt[:login]
|
262
|
+
@servers[i] = @servers[i].map{|h| "#{opt[:login]}@#{h.gsub(/.+@/,'')}"}
|
263
|
+
end
|
264
|
+
|
265
|
+
if opt[:gateway]
|
266
|
+
puts opt[:gateway]
|
267
|
+
@servers[i] = @servers[i].map{|h| "#{opt[:gateway]} -t ssh #{h}"}
|
268
|
+
end
|
304
269
|
end
|
305
270
|
|
306
271
|
|
307
272
|
if @servers.empty?
|
308
|
-
|
309
|
-
|
310
|
-
|
273
|
+
puts 'ERROR: no servers given'
|
274
|
+
puts optparse.help
|
275
|
+
exit
|
311
276
|
end
|
312
277
|
|
313
|
-
|
314
278
|
I2c2.new @servers, ssh_options, @i2_options, @ssh_environment
|
data/i2c2.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: i2c2 1.0.0.
|
5
|
+
# stub: i2c2 1.0.0.beta5 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "i2c2"
|
9
|
-
s.version = "1.0.0.
|
9
|
+
s.version = "1.0.0.beta5"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["dx7", "Wouter de Bie"]
|
14
|
-
s.date = "2019-05
|
14
|
+
s.date = "2019-06-05"
|
15
15
|
s.description = "csshX like - cluster ssh using iTerm2 panes - based on i2cssh"
|
16
16
|
s.email = "dx7@pm.me"
|
17
17
|
s.executables = ["i2c2"]
|
@@ -20,7 +20,6 @@ Gem::Specification.new do |s|
|
|
20
20
|
"README.md"
|
21
21
|
]
|
22
22
|
s.files = [
|
23
|
-
".document",
|
24
23
|
"CHANGELOG.md",
|
25
24
|
"Gemfile",
|
26
25
|
"Gemfile.lock",
|
@@ -35,7 +34,7 @@ Gem::Specification.new do |s|
|
|
35
34
|
"test/helper.rb",
|
36
35
|
"test/test_i2c2.rb"
|
37
36
|
]
|
38
|
-
s.homepage = "
|
37
|
+
s.homepage = "https://github.com/dx7/i2c2"
|
39
38
|
s.licenses = ["MIT"]
|
40
39
|
s.rubygems_version = "3.0.3"
|
41
40
|
s.summary = "csshX like - cluster ssh using iTerm2 panes - based on i2cssh"
|
@@ -45,23 +44,14 @@ Gem::Specification.new do |s|
|
|
45
44
|
|
46
45
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
46
|
s.add_runtime_dependency(%q<rb-scpt>, ["~> 1.0.1"])
|
48
|
-
s.add_development_dependency(%q<
|
49
|
-
s.add_development_dependency(%q<jeweler>, ["= 2.1.2"])
|
50
|
-
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
51
|
-
s.add_development_dependency(%q<builder>, [">= 0"])
|
47
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
52
48
|
else
|
53
49
|
s.add_dependency(%q<rb-scpt>, ["~> 1.0.1"])
|
54
|
-
s.add_dependency(%q<
|
55
|
-
s.add_dependency(%q<jeweler>, ["= 2.1.2"])
|
56
|
-
s.add_dependency(%q<shoulda>, [">= 0"])
|
57
|
-
s.add_dependency(%q<builder>, [">= 0"])
|
50
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
58
51
|
end
|
59
52
|
else
|
60
53
|
s.add_dependency(%q<rb-scpt>, ["~> 1.0.1"])
|
61
|
-
s.add_dependency(%q<
|
62
|
-
s.add_dependency(%q<jeweler>, ["= 2.1.2"])
|
63
|
-
s.add_dependency(%q<shoulda>, [">= 0"])
|
64
|
-
s.add_dependency(%q<builder>, [">= 0"])
|
54
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
65
55
|
end
|
66
56
|
end
|
67
57
|
|
data/lib/i2c2.rb
CHANGED
@@ -1,167 +1,167 @@
|
|
1
1
|
require 'rb-scpt'
|
2
|
+
|
2
3
|
class I2c2
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
# @iterm.create_tab(@profile)
|
35
|
-
@window.create_tab_with_default_profile()
|
36
|
-
@session_index = 0
|
37
|
-
end
|
38
|
-
end
|
39
|
-
@window.select(@window.tabs[1])
|
4
|
+
def initialize servers, ssh_options, i2_options, ssh_environment
|
5
|
+
@ssh_prefix = 'ssh ' + ssh_options.join(' ')
|
6
|
+
@ssh_options = ssh_options
|
7
|
+
@i2_options = i2_options.clone
|
8
|
+
@servers = servers
|
9
|
+
@ssh_environment = ssh_environment
|
10
|
+
|
11
|
+
raise Exception.new 'No servers given' if servers.empty?
|
12
|
+
|
13
|
+
@sys_events = Appscript.app.by_name('System Events')
|
14
|
+
@iterm = Appscript.app.by_name('iTerm')
|
15
|
+
@pane_menu = @sys_events.processes['iTerm2'].menu_bars[1].menu_bar_items['Window'].menus['Window'].menu_items['Select Split Pane'].menus['Select Split Pane']
|
16
|
+
@shell_menu = @sys_events.processes['iTerm2'].menu_bars[1].menu_bar_items['Shell'].menus['Shell']
|
17
|
+
@profile = i2_options.first[:profile] || 'Default'
|
18
|
+
@shell = "/usr/bin/env #{@i2_options.first[:shell] || 'bash'}"
|
19
|
+
@iterm.create_window_with_profile(@profile, :command => "#{@shell} -l")
|
20
|
+
@window = @iterm.current_window
|
21
|
+
|
22
|
+
while !@servers.empty? do
|
23
|
+
compute_geometry
|
24
|
+
split_session
|
25
|
+
start_ssh
|
26
|
+
enable_broadcast if i2_options.first[:broadcast]
|
27
|
+
@servers.shift
|
28
|
+
@i2_options.shift
|
29
|
+
@ssh_environment.shift
|
30
|
+
|
31
|
+
if !@servers.empty? && i2_options.first[:tabs]
|
32
|
+
@window.create_tab_with_default_profile
|
33
|
+
@session_index = 0
|
34
|
+
end
|
40
35
|
end
|
36
|
+
@window.select(@window.tabs[1])
|
37
|
+
end
|
41
38
|
|
42
|
-
|
39
|
+
private
|
43
40
|
def maximize(app_name)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
41
|
+
begin
|
42
|
+
# OSX >= 10.8 has different behavior for full screen. First try out old behavior.
|
43
|
+
fullscreen_bounds = Appscript.app.by_name('Finder').desktop.window.bounds
|
44
|
+
window = @iterm.windows.get.sort_by{|x| x.id_.get}.last
|
45
|
+
window.bounds.set fullscreen_bounds.get
|
46
|
+
rescue
|
47
|
+
@sys_events.processes[app_name].windows.first.attributes['AXFullScreen'].value.set(true)
|
48
|
+
end
|
52
49
|
end
|
53
50
|
|
54
51
|
def compute_geometry
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
else
|
62
|
-
count = @servers.first.size
|
63
|
-
@rows = @i2_options.first[:rows]
|
64
|
-
@columns = @i2_options.first[:columns]
|
65
|
-
end
|
66
|
-
|
67
|
-
if @rows then
|
68
|
-
@columns = (count / @rows.to_f).ceil
|
69
|
-
elsif @columns then
|
70
|
-
@rows = (count / @columns.to_f).ceil
|
71
|
-
else
|
72
|
-
@columns = Math.sqrt(count).ceil
|
73
|
-
@rows = (count / @columns.to_f).ceil
|
74
|
-
end
|
75
|
-
# Quick hack: iTerms default window only supports up to 11 rows and 22 columns
|
76
|
-
# If we surpass either one, we resort to full screen.
|
77
|
-
if @rows > 11 or @columns > 22 then
|
78
|
-
@i2_options.first[:fullscreen] = true
|
52
|
+
# Create geometry when combining and ignore rows/columns preference
|
53
|
+
if @servers.size > 1 && !@i2_options.first[:tabs]
|
54
|
+
count = 0
|
55
|
+
@servers.each do |srv|
|
56
|
+
count += srv.size
|
79
57
|
end
|
58
|
+
else
|
59
|
+
count = @servers.first.size
|
60
|
+
@rows = @i2_options.first[:rows]
|
61
|
+
@columns = @i2_options.first[:columns]
|
62
|
+
end
|
63
|
+
|
64
|
+
if @rows
|
65
|
+
@columns = (count / @rows.to_f).ceil
|
66
|
+
elsif @columns
|
67
|
+
@rows = (count / @columns.to_f).ceil
|
68
|
+
else
|
69
|
+
@columns = Math.sqrt(count).ceil
|
70
|
+
@rows = (count / @columns.to_f).ceil
|
71
|
+
end
|
72
|
+
|
73
|
+
# Quick hack: iTerms default window only supports up to 11 rows and 22 columns
|
74
|
+
# If we surpass either one, we resort to full screen.
|
75
|
+
if @rows > 11 or @columns > 22
|
76
|
+
@i2_options.first[:fullscreen] = true
|
77
|
+
end
|
80
78
|
end
|
81
79
|
|
82
80
|
def split_session
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
81
|
+
left = @pane_menu.menu_items['Select Pane Left']
|
82
|
+
right = @pane_menu.menu_items['Select Pane Right']
|
83
|
+
up = @pane_menu.menu_items['Select Pane Above']
|
84
|
+
down = @pane_menu.menu_items['Select Pane Below']
|
85
|
+
|
86
|
+
split_vert = lambda { @window.current_session.split_vertically_with_same_profile }
|
87
|
+
split_hori = lambda { @window.current_session.split_horizontally_with_same_profile }
|
88
|
+
|
89
|
+
splitmap = {
|
90
|
+
:column => {0 => split_vert, 1 => left, 2 => split_hori, 3=> right, :x => @columns, :y => @rows},
|
91
|
+
:row => {0 => split_hori, 1=> up, 2 => split_vert, 3=> down, :x => @rows, :y => @columns}
|
92
|
+
}
|
93
|
+
|
94
|
+
splitconfig = splitmap[@i2_options.first[:direction]]
|
95
|
+
|
96
|
+
first = true
|
97
|
+
2.upto splitconfig[:x] do
|
98
|
+
splitconfig[0].call
|
99
|
+
end
|
100
|
+
|
101
|
+
2.upto splitconfig[:y] do
|
102
|
+
1.upto splitconfig[:x] do
|
103
|
+
splitconfig[1].click
|
104
|
+
first = false
|
100
105
|
end
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
106
|
-
splitconfig[:x].times do |x|
|
107
|
-
splitconfig[2].call
|
108
|
-
splitconfig[3].click
|
109
|
-
end
|
106
|
+
|
107
|
+
splitconfig[:x].times do |x|
|
108
|
+
splitconfig[2].call
|
109
|
+
splitconfig[3].click
|
110
110
|
end
|
111
|
+
end
|
111
112
|
end
|
112
113
|
|
113
114
|
def enable_broadcast
|
114
|
-
|
115
|
-
|
116
|
-
|
115
|
+
@sys_events.keystroke 'I', :using => :command_down
|
116
|
+
sleep 0.5
|
117
|
+
@sys_events.keystroke "\r"
|
117
118
|
end
|
118
119
|
|
119
120
|
def start_ssh
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
session.write :text => "stty -isig -icanon -echo && echo -e '#{"\n"*100}UNUSED' && cat > /dev/null"
|
164
|
-
end
|
121
|
+
old_size = 0
|
122
|
+
|
123
|
+
1.upto(@rows*@columns) do |i|
|
124
|
+
tab = @window.current_tab
|
125
|
+
session = tab.sessions[i]
|
126
|
+
session.write :text => "#{@shell} -l"
|
127
|
+
|
128
|
+
# Without the tab flag, combine all servers and clusters into one window
|
129
|
+
if !@servers.empty? && (i - old_size) > @servers.first.size && !@i2_options.first[:tabs]
|
130
|
+
old_size = @servers.first.size
|
131
|
+
@servers.shift
|
132
|
+
@i2_options.shift
|
133
|
+
@ssh_environment.shift
|
134
|
+
end
|
135
|
+
|
136
|
+
if @servers.empty?
|
137
|
+
server = nil
|
138
|
+
else
|
139
|
+
server = @servers.first[i-old_size-1]
|
140
|
+
end
|
141
|
+
|
142
|
+
if server
|
143
|
+
send_env = ''
|
144
|
+
|
145
|
+
if @i2_options.first[:rank]
|
146
|
+
@ssh_environment.first['LC_RANK'] = i-1
|
147
|
+
end
|
148
|
+
|
149
|
+
if !@ssh_environment.empty? && !@ssh_environment.first.empty?
|
150
|
+
send_env = "-o SendEnv=#{@ssh_environment.first.keys.join(',')}"
|
151
|
+
session.write :text => "#{@ssh_environment.first.map{|k,v| "export #{k}=#{v}"}.join('; ')}"
|
152
|
+
end
|
153
|
+
|
154
|
+
if @i2_options.first[:sleep]
|
155
|
+
sleep @i2_options.first[:sleep] * i
|
156
|
+
end
|
157
|
+
|
158
|
+
session.write :text => "unset HISTFILE && echo -e \"\\033]50;SetProfile=#{@profile}\\a\" && #{@ssh_prefix} #{send_env} #{server}"
|
159
|
+
else
|
160
|
+
session.write :text => "unset HISTFILE && echo -e \"\\033]50;SetProfile=#{@profile}\\a\""
|
161
|
+
sleep 0.3
|
162
|
+
session.foreground_color.set ([65535,0,0])
|
163
|
+
session.write :text => "stty -isig -icanon -echo && echo -e '#{"\n"*100}UNUSED' && cat > /dev/null"
|
165
164
|
end
|
165
|
+
end
|
166
166
|
end
|
167
167
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: i2c2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.beta5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dx7
|
8
8
|
- Wouter de Bie
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-09-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rb-scpt
|
@@ -25,50 +25,8 @@ dependencies:
|
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: 1.0.1
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
|
-
name: bundler
|
30
|
-
requirement: !ruby/object:Gem::Requirement
|
31
|
-
requirements:
|
32
|
-
- - ">="
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: 1.0.0
|
35
|
-
type: :development
|
36
|
-
prerelease: false
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - ">="
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: 1.0.0
|
42
28
|
- !ruby/object:Gem::Dependency
|
43
29
|
name: jeweler
|
44
|
-
requirement: !ruby/object:Gem::Requirement
|
45
|
-
requirements:
|
46
|
-
- - '='
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version: 2.1.2
|
49
|
-
type: :development
|
50
|
-
prerelease: false
|
51
|
-
version_requirements: !ruby/object:Gem::Requirement
|
52
|
-
requirements:
|
53
|
-
- - '='
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
version: 2.1.2
|
56
|
-
- !ruby/object:Gem::Dependency
|
57
|
-
name: shoulda
|
58
|
-
requirement: !ruby/object:Gem::Requirement
|
59
|
-
requirements:
|
60
|
-
- - ">="
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
63
|
-
type: :development
|
64
|
-
prerelease: false
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - ">="
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: builder
|
72
30
|
requirement: !ruby/object:Gem::Requirement
|
73
31
|
requirements:
|
74
32
|
- - ">="
|
@@ -87,10 +45,10 @@ executables:
|
|
87
45
|
- i2c2
|
88
46
|
extensions: []
|
89
47
|
extra_rdoc_files:
|
48
|
+
- CHANGELOG.md
|
90
49
|
- LICENSE.txt
|
91
50
|
- README.md
|
92
51
|
files:
|
93
|
-
- ".document"
|
94
52
|
- CHANGELOG.md
|
95
53
|
- Gemfile
|
96
54
|
- Gemfile.lock
|
@@ -104,11 +62,11 @@ files:
|
|
104
62
|
- lib/i2c2.rb
|
105
63
|
- test/helper.rb
|
106
64
|
- test/test_i2c2.rb
|
107
|
-
homepage:
|
65
|
+
homepage: https://github.com/dx7/i2c2
|
108
66
|
licenses:
|
109
67
|
- MIT
|
110
68
|
metadata: {}
|
111
|
-
post_install_message:
|
69
|
+
post_install_message:
|
112
70
|
rdoc_options: []
|
113
71
|
require_paths:
|
114
72
|
- lib
|
@@ -123,8 +81,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
81
|
- !ruby/object:Gem::Version
|
124
82
|
version: 1.3.1
|
125
83
|
requirements: []
|
126
|
-
rubygems_version: 3.
|
127
|
-
signing_key:
|
84
|
+
rubygems_version: 3.1.2
|
85
|
+
signing_key:
|
128
86
|
specification_version: 4
|
129
87
|
summary: csshX like - cluster ssh using iTerm2 panes - based on i2cssh
|
130
88
|
test_files: []
|