runssh 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.rdoc +25 -15
- data/completions/_runssh +93 -0
- data/{bin → completions}/runssh_comp.sh +1 -2
- data/lib/runsshlib/cli.rb +6 -2
- data/lib/runsshlib/version.rb +1 -1
- data/spec/runsshlib/cli_spec.rb +45 -1
- metadata +6 -5
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -12,27 +12,31 @@ I am planning to add scp support as well.
|
|
12
12
|
This requires you to have the _ssh_ binary in your path and optionally the
|
13
13
|
<i>ssh-copy-id</i> binary (for copying ssh key).
|
14
14
|
|
15
|
-
|
15
|
+
== Installation
|
16
16
|
You must have ruby[http://www.ruby-lang.org/] and
|
17
17
|
rubygems[http://rubygems.org/] installed and then run:
|
18
18
|
gem install runssh
|
19
19
|
|
20
|
+
=== Zsh Completion
|
21
|
+
Finally we have a <b>fully functional</b> zsh completion. It includes options, subcommands
|
22
|
+
and path completions.
|
23
|
+
|
24
|
+
To install just copy the <tt>completions/_runssh</tt> file which is included in the gem (run
|
25
|
+
<tt>gem contents runssh</tt> to get the path to this file) to one of the directories in your
|
26
|
+
<tt>$fpath</tt>.
|
27
|
+
|
28
|
+
Note: I don't really know how it works. I just read some docs, looked at a few
|
29
|
+
samples (mainly _cvs) and went through a _lot_ of trial and error until it worked for
|
30
|
+
me. I hope it'll work for you as well :)
|
31
|
+
|
20
32
|
=== Bash Completion
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
your bash-completion scripts are).
|
33
|
+
Bash completion is not as complete as the zsh one. It only supports path completions.
|
34
|
+
Since I'm now using zsh, I have very little interest in improving this. Anybody willing
|
35
|
+
to contribute?
|
25
36
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
the file to some place and switch the comments between line 14 and 15. Then add
|
30
|
-
the following to your .zshrc file:
|
31
|
-
autoload bashcompinit
|
32
|
-
bashcompinit
|
33
|
-
source /path/to/modified/runssh_comp.sh
|
34
|
-
This works for me, but I'm only starting with zsh so I hope it will work for you
|
35
|
-
as well.
|
37
|
+
To install just copy the <tt>completions/runssh_comp.sh</tt> file which is included in the gem (run
|
38
|
+
<tt>gem contents runssh</tt> to get the path to this file) to <tt>/etc/bash-completion.d/</tt>
|
39
|
+
(or wherever your bash completion files reside).
|
36
40
|
|
37
41
|
== Usage
|
38
42
|
For usage run _runssh_ without arguments.
|
@@ -132,6 +136,12 @@ and there's no going back ...)
|
|
132
136
|
=== 0.4.1
|
133
137
|
* Doc fixes regarding version skip.
|
134
138
|
|
139
|
+
=== 0.4.2
|
140
|
+
* If, when exporting, the output file exists, the user is prompted for approval.
|
141
|
+
* Completion now works for commands that requires options (e.g. add) even if
|
142
|
+
the required option is not given.
|
143
|
+
* Finally - proper zsh completion :)
|
144
|
+
|
135
145
|
== TODO
|
136
146
|
* Create a _proper_ zsh completion script.
|
137
147
|
* Add scp capabilities.
|
data/completions/_runssh
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#compdef runssh
|
2
|
+
|
3
|
+
_runssh() {
|
4
|
+
_arguments \
|
5
|
+
'(* -)'{-h,--help}'[print help]' \
|
6
|
+
'(* -)'{-v,--version}'[print version and exit]' \
|
7
|
+
'(-f --config-file)'{-f,--config-file}'+[bookmarks file]: : _files' \
|
8
|
+
'(* -)'{-U,--update-config}'[Update config version (after upgrade)]' \
|
9
|
+
'*:: :_runssh_commands'
|
10
|
+
}
|
11
|
+
|
12
|
+
(( $+funtions[_runssh_commands] )) ||
|
13
|
+
_runssh_commands() {
|
14
|
+
if (( CURRENT == 1 )); then
|
15
|
+
_describe -t commands 'runssh commands' "(shell add del update print import export cpid)" && ret=0
|
16
|
+
else
|
17
|
+
# Since we're using a syntax that clears $words we have to get
|
18
|
+
# the custom config file (if given) somehow.
|
19
|
+
[[ -n "$opt_args[-f]" ]] && runssh_config_file="-f $opt_args[-f]"
|
20
|
+
subcommand=$words[1]
|
21
|
+
case $subcommand in
|
22
|
+
shell|del|print|import|export|cpid)
|
23
|
+
_call_function ret _runssh_subcmd_$subcommand
|
24
|
+
;;
|
25
|
+
add|update) # they have the same options
|
26
|
+
_call_function ret _runssh_subcmd_add
|
27
|
+
;;
|
28
|
+
*) # we can not identify the subcommand but since the user
|
29
|
+
# might have used abbreviations, we'll just complete the path.
|
30
|
+
_call_function ret _runssh_path_completions
|
31
|
+
;;
|
32
|
+
esac
|
33
|
+
fi
|
34
|
+
}
|
35
|
+
|
36
|
+
(( $+functions[_runssh_subcmd_shell] )) ||
|
37
|
+
_runssh_subcmd_shell() {
|
38
|
+
_arguments \
|
39
|
+
'(-l --login)'{-l,--login}'+[Override login]: :' \
|
40
|
+
'(-n --host-name)'{-n,--host-name}'+[host to connect to]: :' \
|
41
|
+
'*: :_runssh_path_completions'
|
42
|
+
}
|
43
|
+
|
44
|
+
(( $+functions[_runssh_subcmd_cpid] )) ||
|
45
|
+
_runssh_subcmd_cpid() {
|
46
|
+
_arguments \
|
47
|
+
'(-i --identity-file)'{-i,--identity-file}'+[Ssh key to copy]: : _files' \
|
48
|
+
'*: :_runssh_path_completions'
|
49
|
+
}
|
50
|
+
|
51
|
+
(( $+functions[_runssh_subcmd_import] )) ||
|
52
|
+
_runssh_subcmd_import() {
|
53
|
+
_arguments \
|
54
|
+
'(-i --input-file)'{-i,--input-file}'+[Yaml file to import]: : _files'\
|
55
|
+
}
|
56
|
+
|
57
|
+
(( $+functions[_runssh_subcmd_export] )) ||
|
58
|
+
_runssh_subcmd_export() {
|
59
|
+
_arguments \
|
60
|
+
'(-o --output-file)'{-o,--output-file}'+[File to export to]: : _files'\
|
61
|
+
}
|
62
|
+
|
63
|
+
(( $+functions[_runssh_subcmd_del] )) ||
|
64
|
+
_runssh_subcmd_del() {
|
65
|
+
_arguments \
|
66
|
+
'(-y --yes)'{-y,--yes}'[Delete without asking]' \
|
67
|
+
'*: :_runssh_path_completions'
|
68
|
+
}
|
69
|
+
|
70
|
+
(( $+functions[_runssh_subcmd_print] )) ||
|
71
|
+
_runssh_subcmd_print() {
|
72
|
+
_arguments \
|
73
|
+
'*: :_runssh_path_completions'
|
74
|
+
}
|
75
|
+
|
76
|
+
(( $+functions[_runssh_subcmd_add] )) ||
|
77
|
+
_runssh_subcmd_add() {
|
78
|
+
_arguments \
|
79
|
+
'(-l --login)'{-l,--login}'+[Login user]: :' \
|
80
|
+
'(-n --host-name)'{-n,--host-name}'+[host to connect to]: :' \
|
81
|
+
'(-L --local-tunnel)'{-L,--local-tunnel}'+[Local tunnel definition]: :' \
|
82
|
+
{\*-o,\*--option}'+[Ssh option]: :' \
|
83
|
+
'(-N --no-host-key-checking)'{-N,--no-host-key-checking}"[Don't verify host key!]" \
|
84
|
+
'*: :_runssh_path_completions'
|
85
|
+
}
|
86
|
+
|
87
|
+
# Call 'runssh ... ?' and get possible completions
|
88
|
+
(( $+functions[_runssh_path_completions] )) ||
|
89
|
+
_runssh_path_completions() {
|
90
|
+
completion_command="runssh $runssh_config_file $words[0,CURRENT-1] \? 2>/dev/null"
|
91
|
+
path_completions="( $(_call_program paths $completion_command ) )"
|
92
|
+
_describe -t paths 'available paths' $path_completions && ret=0
|
93
|
+
}
|
@@ -11,8 +11,7 @@ function _runssh () {
|
|
11
11
|
fi
|
12
12
|
# complete path or commands according to the position.
|
13
13
|
if [ ${COMP_CWORD} -gt $COM_POSITION ]; then
|
14
|
-
options=$(${COMP_WORDS[@]:0:COMP_CWORD} ? 2>/dev/null)
|
15
|
-
# options=$(${COMP_WORDS[0,COMP_CWORD-1]} ? 2>/dev/null) # ZSH
|
14
|
+
options=$(${COMP_WORDS[@]:0:COMP_CWORD} ? 2>/dev/null)
|
16
15
|
elif [ $COMP_CWORD -eq $COM_POSITION ]; then
|
17
16
|
options="shell cpid add del update print import export"
|
18
17
|
fi
|
data/lib/runsshlib/cli.rb
CHANGED
@@ -61,7 +61,7 @@ EOS
|
|
61
61
|
# workaround to enable 'help COMMAND' functionality.
|
62
62
|
if args.first == 'help'; args.shift; args << '-h'; end
|
63
63
|
# indicate path completion request
|
64
|
-
@completion_requested = args.delete('?')
|
64
|
+
@completion_requested = args.delete('?') ? true : false # flag for required options
|
65
65
|
@cmd = extract_subcommand(args)
|
66
66
|
@options = parse_subcommand(@cmd, args)
|
67
67
|
@c = init_config
|
@@ -263,7 +263,7 @@ EOH
|
|
263
263
|
options = Trollop::options(args) do
|
264
264
|
banner help
|
265
265
|
opt :host_name, 'The name or address of the host (e.g, host.example.com).',
|
266
|
-
:short => :n, :type => :string, :required =>
|
266
|
+
:short => :n, :type => :string, :required => @completion_requested
|
267
267
|
opt :login, 'The login to connect as.',
|
268
268
|
:type => :string
|
269
269
|
opt :local_tunnel, "Tunnel definition (see description above).",
|
@@ -403,6 +403,10 @@ EOS
|
|
403
403
|
|
404
404
|
# we don't use path here, it's just for easier invocation
|
405
405
|
def run_export(path)
|
406
|
+
if File.exist? @options[:output_file]
|
407
|
+
question = "Output file (#{@options[:output_file]}) exists!. Overwrite? [yes/no] "
|
408
|
+
agree_or_abort question, 'Cancelled'
|
409
|
+
end
|
406
410
|
@c.export(@options[:output_file])
|
407
411
|
end
|
408
412
|
|
data/lib/runsshlib/version.rb
CHANGED
data/spec/runsshlib/cli_spec.rb
CHANGED
@@ -21,7 +21,7 @@ require 'stringio'
|
|
21
21
|
require 'yaml'
|
22
22
|
|
23
23
|
describe "The CLI interface" do
|
24
|
-
context "
|
24
|
+
context "global options parsing" do
|
25
25
|
it "should correctly process the -f argument" do
|
26
26
|
cli = RunSSHLib::CLI.new(%W(-f #{TMP_FILE} print test))
|
27
27
|
global_options = cli.instance_variable_get :@global_options
|
@@ -48,7 +48,9 @@ describe "The CLI interface" do
|
|
48
48
|
end.to exit_abnormaly
|
49
49
|
@buf.should match(/invalid command/)
|
50
50
|
end
|
51
|
+
end
|
51
52
|
|
53
|
+
context "completion mechanism" do
|
52
54
|
it "displays completions and exit if requested" do
|
53
55
|
import_fixtures
|
54
56
|
capture(:stdout) {
|
@@ -57,6 +59,15 @@ describe "The CLI interface" do
|
|
57
59
|
@buf.should include("cust1")
|
58
60
|
@buf.should include("cust2")
|
59
61
|
end
|
62
|
+
|
63
|
+
it "displays completion even if required option for subcommand is missing" do
|
64
|
+
import_fixtures
|
65
|
+
capture(:stdout) {
|
66
|
+
RunSSHLib::CLI.new(%W(-f #{TMP_FILE} update ?)).run
|
67
|
+
}
|
68
|
+
@buf.should include("cust1")
|
69
|
+
@buf.should include("cust2")
|
70
|
+
end
|
60
71
|
end
|
61
72
|
|
62
73
|
context "help" do
|
@@ -214,6 +225,39 @@ describe "The CLI interface" do
|
|
214
225
|
end
|
215
226
|
end
|
216
227
|
|
228
|
+
describe "export subcommand" do
|
229
|
+
context "when export file exists" do
|
230
|
+
let(:cli) {
|
231
|
+
RunSSHLib::CLI::new(%W(-f #{TMP_FILE} export -o #{TMP_YML}))
|
232
|
+
}
|
233
|
+
|
234
|
+
before(:each) do
|
235
|
+
File.open(TMP_YML, 'w') { |io| io.write "" }
|
236
|
+
end
|
237
|
+
|
238
|
+
it "overwrites the file if the user approves the prompt" do
|
239
|
+
capture(:stderr) do
|
240
|
+
capture(:stdout, 'yes') do
|
241
|
+
cli.run
|
242
|
+
end
|
243
|
+
end
|
244
|
+
@buf.should include('Overwrite?')
|
245
|
+
@buf.should include(TMP_YML)
|
246
|
+
IO.read(TMP_YML).should_not == ""
|
247
|
+
end
|
248
|
+
|
249
|
+
it "correctly cancels exporting if answered no at the prompt" do
|
250
|
+
capture(:stdout) do
|
251
|
+
capture(:stderr, 'no') do
|
252
|
+
expect { cli.run }.to exit_abnormaly
|
253
|
+
end
|
254
|
+
end
|
255
|
+
@buf.should include('Cancelled')
|
256
|
+
IO.read(TMP_YML).should == ''
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
217
261
|
context "Add bookmark with ssh options" do
|
218
262
|
it "adds options specified with '-o' to the '--no-host-key-checking' options" do
|
219
263
|
options = %W(-f #{TMP_FILE} add -o ForwardAgent=true --no-host-key-checking -n some.host one two)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: runssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
9
|
+
- 2
|
10
|
+
version: 0.4.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Haim Ashkenazi
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-07 00:00:00 +03:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -71,7 +71,8 @@ files:
|
|
71
71
|
- Rakefile
|
72
72
|
- autotest/discover.rb
|
73
73
|
- bin/runssh
|
74
|
-
-
|
74
|
+
- completions/_runssh
|
75
|
+
- completions/runssh_comp.sh
|
75
76
|
- features/add_bookmarks.feature
|
76
77
|
- features/cli_help.feature
|
77
78
|
- features/copy_id.feature
|