eftcmdr 0.4.0
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.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/README.md +77 -0
- data/Rakefile +70 -0
- data/bin/eftcmdr +5 -0
- data/bin/eftcmdr-ssh-setup +8 -0
- data/eftcmdr.gemspec +33 -0
- data/examples/bar.apps +1 -0
- data/examples/bar.yml +70 -0
- data/examples/foo.apps +2 -0
- data/examples/foo.yml +70 -0
- data/examples/hello.yml +6 -0
- data/examples/qux.yml +66 -0
- data/lib/eftcmdr/version.rb +4 -0
- data/lib/eftcmdr.rb +258 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c026792651e7d592cd7e95b0cdbeba4b48a72a34
|
4
|
+
data.tar.gz: 90f7c70c580bfa46dcd83a809dc241a9115f77fc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 12f6227308d8c61cca91fd372776dc89f628dc3bc3ce06e63dac725ba0217b67d7b2d8fcff56f5840e22c82162ea4bd805237df4a16c61295c6175121f452226
|
7
|
+
data.tar.gz: 7519af3448265a958f276452a7e9fd4d117ecf986bc61b2cc03f6552e37551b955f528e1656ee87b6ac8c36c20b26bc72b53316d5d540d760b6e5fa08f8aaf28
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown
|
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
[]: {{{1
|
2
|
+
|
3
|
+
File : README.md
|
4
|
+
Maintainer : Felix C. Stegerman <flx@obfusk.net>
|
5
|
+
Date : 2014-02-20
|
6
|
+
|
7
|
+
Copyright : Copyright (C) 2014 Felix C. Stegerman
|
8
|
+
Version : v0.4.0
|
9
|
+
|
10
|
+
[]: }}}1
|
11
|
+
|
12
|
+
[](http://badge.fury.io/rb/eftcmdr)
|
13
|
+
|
14
|
+
## Description
|
15
|
+
[]: {{{1
|
16
|
+
|
17
|
+
eftcmdr - yaml + ruby + whiptail
|
18
|
+
|
19
|
+
EftCmdr is a yaml dsl that wraps `whiptail` [1] to display dialog
|
20
|
+
boxes. It provides a yaml dsl on top of `eft` [2]. See `examples/`
|
21
|
+
for examples.
|
22
|
+
|
23
|
+
```yaml
|
24
|
+
ask: ask_name
|
25
|
+
text: What is your name?
|
26
|
+
then:
|
27
|
+
eval: eval_hello
|
28
|
+
code: |
|
29
|
+
puts "Hello, #{ctx[:ask_name]}!"
|
30
|
+
```
|
31
|
+
|
32
|
+
```bash
|
33
|
+
$ eftcmdr examples/hello.yml
|
34
|
+
```
|
35
|
+
|
36
|
+
### SSH
|
37
|
+
|
38
|
+
You can use `eftcmdr-ssh-setup` to generate a
|
39
|
+
`~/.ssh/authorized_keys` from `~/.eftcmdr.d/*.{pub,yml}` (see
|
40
|
+
`examples/`). This allows you to use `eftcmdr` to provide a menu
|
41
|
+
over `ssh -t` that allows selected users to perform selected
|
42
|
+
actions.
|
43
|
+
|
44
|
+
**NB**: be careful what you allow -- access to e.g. a rails console
|
45
|
+
makes it trivial to get complete shell access.
|
46
|
+
|
47
|
+
[]: }}}1
|
48
|
+
|
49
|
+
## Specs & Docs
|
50
|
+
|
51
|
+
```bash
|
52
|
+
$ rake spec # TODO
|
53
|
+
$ rake docs
|
54
|
+
```
|
55
|
+
|
56
|
+
## TODO
|
57
|
+
|
58
|
+
* gauge?
|
59
|
+
* options?
|
60
|
+
* specs! (how to automate tests of whiptail? - I don't know!)
|
61
|
+
|
62
|
+
## License
|
63
|
+
|
64
|
+
LGPLv3+ [3].
|
65
|
+
|
66
|
+
## References
|
67
|
+
|
68
|
+
[1] Newt (and whiptail)
|
69
|
+
--- http://en.wikipedia.org/wiki/Newt_(programming_library)
|
70
|
+
|
71
|
+
[2] eft
|
72
|
+
--- https://github.com/obfusk/eft
|
73
|
+
|
74
|
+
[3] GNU Lesser General Public License, version 3
|
75
|
+
--- http://www.gnu.org/licenses/lgpl-3.0.html
|
76
|
+
|
77
|
+
[]: ! ( vim: set tw=70 sw=2 sts=2 et fdm=marker : )
|
data/Rakefile
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
desc 'Run specs'
|
2
|
+
task :spec do
|
3
|
+
puts 'No automated tests yet - please manually test the examples'
|
4
|
+
# sh 'rspec -c'
|
5
|
+
end
|
6
|
+
|
7
|
+
desc 'Run specs verbosely'
|
8
|
+
task 'spec:verbose' do
|
9
|
+
puts 'No automated tests yet - please manually test the examples'
|
10
|
+
# sh 'rspec -cfd'
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Run specs verbosely, view w/ less'
|
14
|
+
task 'spec:less' do
|
15
|
+
puts 'No automated tests yet - please manually test the examples'
|
16
|
+
# sh 'rspec -cfd --tty | less -R'
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'Check for warnings'
|
20
|
+
task :warn do
|
21
|
+
sh 'ruby -w -I lib -r eftcmdr -e ""'
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Run example foo'
|
25
|
+
task 'example:foo' do
|
26
|
+
sh 'ruby -w -I lib bin/eftcmdr examples/foo.yml'
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'Run example bar'
|
30
|
+
task 'example:bar' do
|
31
|
+
sh 'ruby -w -I lib bin/eftcmdr examples/bar.yml'
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'Run example qux'
|
35
|
+
task 'example:qux' do
|
36
|
+
sh 'ruby -w -I lib bin/eftcmdr examples/qux.yml'
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'Run example hello'
|
40
|
+
task 'example:hello' do
|
41
|
+
sh 'ruby -w -I lib bin/eftcmdr examples/hello.yml'
|
42
|
+
end
|
43
|
+
|
44
|
+
desc 'Generate docs'
|
45
|
+
task :docs do
|
46
|
+
sh 'yardoc | cat'
|
47
|
+
end
|
48
|
+
|
49
|
+
desc 'List undocumented objects'
|
50
|
+
task 'docs:undoc' do
|
51
|
+
sh 'yard stats --list-undoc'
|
52
|
+
end
|
53
|
+
|
54
|
+
desc 'Cleanup'
|
55
|
+
task :clean do
|
56
|
+
sh 'rm -rf .yardoc/ doc/ *.gem'
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'Build SNAPSHOT gem'
|
60
|
+
task :snapshot do
|
61
|
+
v = Time.new.strftime '%Y%m%d%H%M%S'
|
62
|
+
f = 'lib/eftcmdr/version.rb'
|
63
|
+
sh "sed -ri~ 's!(SNAPSHOT)!\\1.#{v}!' #{f}"
|
64
|
+
sh 'gem build eftcmdr.gemspec'
|
65
|
+
end
|
66
|
+
|
67
|
+
desc 'Undo SNAPSHOT gem'
|
68
|
+
task 'snapshot:undo' do
|
69
|
+
sh 'git checkout -- lib/eftcmdr/version.rb'
|
70
|
+
end
|
data/bin/eftcmdr
ADDED
data/eftcmdr.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.expand_path('../lib/eftcmdr/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'eftcmdr'
|
5
|
+
s.homepage = 'https://github.com/obfusk/eftcmdr'
|
6
|
+
s.summary = 'yaml + ruby + whiptail'
|
7
|
+
|
8
|
+
s.description = <<-END.gsub(/^ {4}/, '')
|
9
|
+
EftCmdr is a yaml dsl that wraps whiptail to display dialog boxes.
|
10
|
+
It provides a yaml dsl on top of eft. See examples/ for examples.
|
11
|
+
END
|
12
|
+
|
13
|
+
s.version = EftCmdr::VERSION
|
14
|
+
s.date = EftCmdr::DATE
|
15
|
+
|
16
|
+
s.authors = [ 'Felix C. Stegerman' ]
|
17
|
+
s.email = %w{ flx@obfusk.net }
|
18
|
+
|
19
|
+
s.licenses = %w{ LGPLv3+ }
|
20
|
+
|
21
|
+
s.executables = %w{ eftcmdr eftcmdr-ssh-setup }
|
22
|
+
s.files = %w{ .yardopts README.md Rakefile eftcmdr.gemspec } \
|
23
|
+
+ Dir['examples/**/*.{yml,apps}'] \
|
24
|
+
+ Dir['lib/**/*.rb']
|
25
|
+
|
26
|
+
s.add_runtime_dependency 'eft'
|
27
|
+
s.add_runtime_dependency 'obfusk-util', '>= 0.5.0'
|
28
|
+
|
29
|
+
s.add_development_dependency 'rake'
|
30
|
+
# s.add_development_dependency 'rspec'
|
31
|
+
|
32
|
+
s.required_ruby_version = '>= 1.9.1'
|
33
|
+
end
|
data/examples/bar.apps
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
qux quux
|
data/examples/bar.yml
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
_apps: &_apps
|
2
|
+
<% apps = file.sub(/\.yml\z/, '.apps') %>
|
3
|
+
<% if File.exists? apps %>
|
4
|
+
<% File.read(apps).split.each do |x| %>
|
5
|
+
- tag: <%= x %>
|
6
|
+
text: The <%= x %> app
|
7
|
+
<% end %>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
_menu_commands: &_menu_commands
|
11
|
+
menu: menu_commands
|
12
|
+
title: commands
|
13
|
+
text: Choose a command to run
|
14
|
+
choices:
|
15
|
+
|
16
|
+
- tag: log
|
17
|
+
text: view log
|
18
|
+
then:
|
19
|
+
ask: ask_lines
|
20
|
+
text: How many lines?
|
21
|
+
default: 100
|
22
|
+
validate: \A\d+\z
|
23
|
+
then:
|
24
|
+
eval: eval_view_log
|
25
|
+
code: |
|
26
|
+
sh! 'echo cd "$1" && echo tail -n "$2" logfile', app, ctx[:ask_lines]
|
27
|
+
|
28
|
+
- tag: console
|
29
|
+
text: rails console
|
30
|
+
then:
|
31
|
+
eval: eval_rails_console
|
32
|
+
code: |
|
33
|
+
sh! 'echo cd "$1" && echo rails console', app
|
34
|
+
|
35
|
+
- tag: psql
|
36
|
+
text: postgresql console
|
37
|
+
then:
|
38
|
+
eval: eval_psql
|
39
|
+
code: |
|
40
|
+
sh! 'echo psql "$1"', app
|
41
|
+
|
42
|
+
- tag: reset
|
43
|
+
text: git reset
|
44
|
+
then:
|
45
|
+
show_text: show_text_git_status
|
46
|
+
code: |
|
47
|
+
shc!('echo cd "$1" && echo git fetch --all && echo git status',
|
48
|
+
app, merge: true).stdout
|
49
|
+
then:
|
50
|
+
ask_yesno: ask_yesno_git_reset
|
51
|
+
text: Are you sure?
|
52
|
+
then:
|
53
|
+
eval: eval_git_reset
|
54
|
+
code: |
|
55
|
+
sh! 'echo cd "$1" && echo git reset --hard', app
|
56
|
+
else:
|
57
|
+
eval: eval_git_reset_cancelled
|
58
|
+
code: |
|
59
|
+
puts 'git reset cancelled'
|
60
|
+
|
61
|
+
menu: menu_apps
|
62
|
+
title: apps
|
63
|
+
text: Choose an app
|
64
|
+
choices: *_apps
|
65
|
+
then:
|
66
|
+
eval: eval_menu_apps
|
67
|
+
code: |
|
68
|
+
app = ctx[:menu_apps][:tag]
|
69
|
+
then: *_menu_commands
|
70
|
+
|
data/examples/foo.apps
ADDED
data/examples/foo.yml
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
_apps: &_apps
|
2
|
+
<% apps = file.sub(/\.yml\z/, '.apps') %>
|
3
|
+
<% if File.exists? apps %>
|
4
|
+
<% File.read(apps).split.each do |x| %>
|
5
|
+
- tag: <%= x %>
|
6
|
+
text: The <%= x %> app
|
7
|
+
<% end %>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
_menu_commands: &_menu_commands
|
11
|
+
menu: menu_commands
|
12
|
+
title: commands
|
13
|
+
text: Choose a command to run
|
14
|
+
choices:
|
15
|
+
|
16
|
+
- tag: log
|
17
|
+
text: view log
|
18
|
+
then:
|
19
|
+
ask: ask_lines
|
20
|
+
text: How many lines?
|
21
|
+
default: 100
|
22
|
+
validate: \A\d+\z
|
23
|
+
then:
|
24
|
+
eval: eval_view_log
|
25
|
+
code: |
|
26
|
+
sh! 'echo cd "$1" && echo tail -n "$2" logfile', app, ctx[:ask_lines]
|
27
|
+
|
28
|
+
- tag: console
|
29
|
+
text: rails console
|
30
|
+
then:
|
31
|
+
eval: eval_rails_console
|
32
|
+
code: |
|
33
|
+
sh! 'echo cd "$1" && echo rails console', app
|
34
|
+
|
35
|
+
- tag: psql
|
36
|
+
text: postgresql console
|
37
|
+
then:
|
38
|
+
eval: eval_psql
|
39
|
+
code: |
|
40
|
+
sh! 'echo psql "$1"', app
|
41
|
+
|
42
|
+
- tag: reset
|
43
|
+
text: git reset
|
44
|
+
then:
|
45
|
+
show_text: show_text_git_status
|
46
|
+
code: |
|
47
|
+
shc!('echo cd "$1" && echo git fetch --all && echo git status',
|
48
|
+
app, merge: true).stdout
|
49
|
+
then:
|
50
|
+
ask_yesno: ask_yesno_git_reset
|
51
|
+
text: Are you sure?
|
52
|
+
then:
|
53
|
+
eval: eval_git_reset
|
54
|
+
code: |
|
55
|
+
sh! 'echo cd "$1" && echo git reset --hard', app
|
56
|
+
else:
|
57
|
+
eval: eval_git_reset_cancelled
|
58
|
+
code: |
|
59
|
+
puts 'git reset cancelled'
|
60
|
+
|
61
|
+
menu: menu_apps
|
62
|
+
title: apps
|
63
|
+
text: Choose an app
|
64
|
+
choices: *_apps
|
65
|
+
then:
|
66
|
+
eval: eval_menu_apps
|
67
|
+
code: |
|
68
|
+
app = ctx[:menu_apps][:tag]
|
69
|
+
then: *_menu_commands
|
70
|
+
|
data/examples/hello.yml
ADDED
data/examples/qux.yml
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
<% require 'securerandom' %>
|
2
|
+
|
3
|
+
_menu_stuff: &_menu_stuff
|
4
|
+
menu: menu_stuff
|
5
|
+
title: stuff
|
6
|
+
text: Choose something
|
7
|
+
choices:
|
8
|
+
|
9
|
+
- tag: secret
|
10
|
+
text: secret stuff
|
11
|
+
then:
|
12
|
+
ask_pass: ask_pass_secret
|
13
|
+
text: Enter the secret password
|
14
|
+
then:
|
15
|
+
eval: eval_secret
|
16
|
+
code: |
|
17
|
+
sh! 'echo the secret is "$1!"', ctx[:ask_pass_secret].to_s
|
18
|
+
|
19
|
+
- tag: special
|
20
|
+
text: special stuff
|
21
|
+
then:
|
22
|
+
show_text: show_text_services
|
23
|
+
file: /etc/services
|
24
|
+
scroll: true
|
25
|
+
then: *_menu_stuff
|
26
|
+
|
27
|
+
- tag: check
|
28
|
+
text: Checkboxes
|
29
|
+
then:
|
30
|
+
check: check_foo
|
31
|
+
text: Choose!
|
32
|
+
choices:
|
33
|
+
- tag: first
|
34
|
+
text: '#1'
|
35
|
+
- tag: second
|
36
|
+
text: '#2'
|
37
|
+
then:
|
38
|
+
eval: eval_check
|
39
|
+
code: |
|
40
|
+
ctx[:check_foo].length > 0
|
41
|
+
then:
|
42
|
+
show_msg: show_msg_more
|
43
|
+
text: you selected one or more
|
44
|
+
else:
|
45
|
+
show_msg: show_msg_securerandom
|
46
|
+
code: |
|
47
|
+
SecureRandom.hex 32
|
48
|
+
esc:
|
49
|
+
eval: eval_esc
|
50
|
+
code: |
|
51
|
+
puts 'ESCAPED!'
|
52
|
+
|
53
|
+
menu: menu_choose
|
54
|
+
title: choose
|
55
|
+
text: Choose
|
56
|
+
selected: two
|
57
|
+
choices:
|
58
|
+
- tag: one
|
59
|
+
text: 1
|
60
|
+
- tag: two
|
61
|
+
text: 2
|
62
|
+
then: *_menu_stuff
|
63
|
+
cancel:
|
64
|
+
eval: eval_cancelled
|
65
|
+
code: |
|
66
|
+
puts 'CANCELLED!'
|
data/lib/eftcmdr.rb
ADDED
@@ -0,0 +1,258 @@
|
|
1
|
+
# -- ; {{{1
|
2
|
+
#
|
3
|
+
# File : eftcmdr.rb
|
4
|
+
# Maintainer : Felix C. Stegerman <flx@obfusk.net>
|
5
|
+
# Date : 2014-02-20
|
6
|
+
#
|
7
|
+
# Copyright : Copyright (C) 2014 Felix C. Stegerman
|
8
|
+
# Licence : LGPLv3+
|
9
|
+
#
|
10
|
+
# -- ; }}}1
|
11
|
+
|
12
|
+
require 'erb'
|
13
|
+
require 'yaml'
|
14
|
+
|
15
|
+
require 'eft'
|
16
|
+
require 'obfusk/util/sh'
|
17
|
+
|
18
|
+
module EftCmdr
|
19
|
+
|
20
|
+
class InvalidFileNameError < RuntimeError; end
|
21
|
+
class InvalidSpecError < RuntimeError; end
|
22
|
+
class ValidationError < RuntimeError; end
|
23
|
+
|
24
|
+
# --
|
25
|
+
|
26
|
+
# state: context, data, binding
|
27
|
+
class State < Struct.new(:ctx, :data, :scope) # {{{1
|
28
|
+
def initialize(ctx, data, scope = nil)
|
29
|
+
super ctx, data, scope || data._binding
|
30
|
+
end
|
31
|
+
def merge_ctx(ctx_)
|
32
|
+
self.class.new ctx.merge(ctx_), data, scope
|
33
|
+
end
|
34
|
+
def eval(code)
|
35
|
+
data.ctx = ctx; scope.eval code
|
36
|
+
end
|
37
|
+
end # }}}1
|
38
|
+
|
39
|
+
# data: file, args, context
|
40
|
+
class Data < Struct.new(:file, :args, :ctx)
|
41
|
+
%w{ sh sh? sh! shc shc? shc! }.each do |m|
|
42
|
+
define_method(m) { |*a,&b| Obfusk::Util.send(m, *a, &b) }
|
43
|
+
end
|
44
|
+
def _binding; binding; end
|
45
|
+
end
|
46
|
+
|
47
|
+
# --
|
48
|
+
|
49
|
+
SSH_LINE = -> cmd, key, comment {
|
50
|
+
%Q{command="#{cmd}",no-agent-forwarding,no-port-forwarding,} +
|
51
|
+
%Q{no-X11-forwarding #{key} #{comment}}
|
52
|
+
}
|
53
|
+
|
54
|
+
ACTIONS = %w{ eval menu check radio ask ask_pass ask_yesno
|
55
|
+
show_msg show_text }
|
56
|
+
|
57
|
+
# --
|
58
|
+
|
59
|
+
# run self.$ACTION
|
60
|
+
def self.run(spec, state = new_state)
|
61
|
+
ACTIONS.each { |x| return self.send x, spec, state if spec[x] }
|
62
|
+
raise InvalidSpecError, 'no action found'
|
63
|
+
end
|
64
|
+
|
65
|
+
# run w/ merged ctx if there is a next action to run
|
66
|
+
def self.then_run(spec, state, ctx = {})
|
67
|
+
run spec, state.merge_ctx(ctx) if spec
|
68
|
+
end
|
69
|
+
|
70
|
+
# --
|
71
|
+
|
72
|
+
# evaluate and continue
|
73
|
+
def self.eval(spec, state, &b)
|
74
|
+
v = state.eval spec['code']
|
75
|
+
n = v ? spec['then'] : spec['else'] || spec['then']
|
76
|
+
b ? b[v,n] : then_run(n, state, spec['eval'].to_sym => v)
|
77
|
+
end
|
78
|
+
|
79
|
+
# --
|
80
|
+
|
81
|
+
# new state
|
82
|
+
def self.new_state(file = nil, args = [])
|
83
|
+
State.new({}, Data.new(file, args, nil))
|
84
|
+
end
|
85
|
+
|
86
|
+
# load yaml (parsed w/ ERB)
|
87
|
+
# @return [Array] [yaml,state]
|
88
|
+
def self.load_yaml(file, *args)
|
89
|
+
s = new_state file, args
|
90
|
+
y = YAML.load ERB.new(File.read(file)).result s.scope
|
91
|
+
[y,s]
|
92
|
+
end
|
93
|
+
|
94
|
+
# handle `on_{cancel,esc}`
|
95
|
+
def self.on_cancel_esc(e, spec, state)
|
96
|
+
e.on_cancel { then_run spec['cancel'], state } \
|
97
|
+
if e.respond_to? :on_cancel
|
98
|
+
e.on_esc { then_run spec['esc'], state } \
|
99
|
+
if e.respond_to? :on_esc
|
100
|
+
end
|
101
|
+
|
102
|
+
# helper
|
103
|
+
def self._opts(spec, more = {})
|
104
|
+
{ title: spec['title'], scroll: spec['scroll'] } .merge more
|
105
|
+
end
|
106
|
+
|
107
|
+
# --
|
108
|
+
|
109
|
+
# menu
|
110
|
+
def self.menu(spec, state) # {{{1
|
111
|
+
Eft.menu spec['text'],
|
112
|
+
_opts(spec, selected: spec['selected']) do |m|
|
113
|
+
spec['choices'].each do |c|
|
114
|
+
m.on(c['tag'], c['text']) do |x|
|
115
|
+
then_run (c['then'] || spec['then']), state,
|
116
|
+
spec['menu'].to_sym => { tag: c['tag'], text: c['text'] }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
on_cancel_esc m, spec, state
|
120
|
+
end
|
121
|
+
end # }}}1
|
122
|
+
|
123
|
+
# checkboxes
|
124
|
+
def self.check(spec, state) # {{{1
|
125
|
+
Eft.check spec['text'], _opts(spec) do |cb|
|
126
|
+
spec['choices'].each do |c|
|
127
|
+
cb.choice c['tag'], c['text'], c['selected']
|
128
|
+
end
|
129
|
+
cb.on_ok do |choices|
|
130
|
+
then_run spec['then'], state, spec['check'].to_sym => choices
|
131
|
+
end
|
132
|
+
on_cancel_esc cb, spec, state
|
133
|
+
end
|
134
|
+
end # }}}1
|
135
|
+
|
136
|
+
# radiolist
|
137
|
+
def self.radio(spec, state) # {{{1
|
138
|
+
Eft.radio spec['text'],
|
139
|
+
_opts(spec, selected: spec['selected']) do |r|
|
140
|
+
spec['choices'].each do |c|
|
141
|
+
c.choice c['tag'], c['text']
|
142
|
+
end
|
143
|
+
r.on_ok do |choice|
|
144
|
+
then_run spec['then'], state, spec['radio'].to_sym => choice
|
145
|
+
end
|
146
|
+
on_cancel_esc r, spec, state
|
147
|
+
end
|
148
|
+
end # }}}1
|
149
|
+
|
150
|
+
# --
|
151
|
+
|
152
|
+
# ask
|
153
|
+
def self.ask(spec, state) # {{{1
|
154
|
+
Eft.ask spec['text'], _opts(spec, default: spec['default']) do |q|
|
155
|
+
q.on_ok do |x|
|
156
|
+
x =~ Regexp.new(spec['validate']) \
|
157
|
+
or raise ValidationError, "#{x} !~ #{spec['validate']}" \
|
158
|
+
if spec['validate']
|
159
|
+
then_run spec['then'], state, spec['ask'].to_sym => x
|
160
|
+
end
|
161
|
+
on_cancel_esc q, spec, state
|
162
|
+
end
|
163
|
+
end # }}}1
|
164
|
+
|
165
|
+
# ask password
|
166
|
+
def self.ask_pass(spec, state) # {{{1
|
167
|
+
Eft.ask_pass spec['text'], _opts(spec) do |q|
|
168
|
+
q.on_ok do |x|
|
169
|
+
then_run spec['then'], state, spec['ask_pass'].to_sym => x
|
170
|
+
end
|
171
|
+
on_cancel_esc q, spec, state
|
172
|
+
end
|
173
|
+
end # }}}1
|
174
|
+
|
175
|
+
# ask yes/no
|
176
|
+
def self.ask_yesno(spec, state) # {{{1
|
177
|
+
Eft.ask_yesno spec['text'], _opts(spec) do |q|
|
178
|
+
q.on_yes do
|
179
|
+
then_run spec['then'], state, spec['ask_yesno'].to_sym => true
|
180
|
+
end
|
181
|
+
q.on_no do
|
182
|
+
then_run (spec['else'] || spec['then']), state,
|
183
|
+
spec['ask_yesno'].to_sym => false
|
184
|
+
end
|
185
|
+
on_cancel_esc q, spec, state
|
186
|
+
end
|
187
|
+
end # }}}1
|
188
|
+
|
189
|
+
# --
|
190
|
+
|
191
|
+
# show message
|
192
|
+
def self.show_msg(spec, state) # {{{1
|
193
|
+
o = _opts(spec)
|
194
|
+
if spec['code']
|
195
|
+
eval spec, state do |v,n|
|
196
|
+
Eft.show_msg v, o do |t|
|
197
|
+
t.on_ok { then_run n, state, spec['show_msg'].to_sym => v }
|
198
|
+
on_cancel_esc t, spec, state
|
199
|
+
end
|
200
|
+
end
|
201
|
+
elsif spec['text']
|
202
|
+
Eft.show_msg spec['text'], o do |t|
|
203
|
+
t.on_ok { then_run spec['then'], state }
|
204
|
+
on_cancel_esc t, spec, state
|
205
|
+
end
|
206
|
+
else
|
207
|
+
raise InvalidSpecError, 'show_msg needs code or text'
|
208
|
+
end
|
209
|
+
end # }}}1
|
210
|
+
|
211
|
+
# show text/file
|
212
|
+
def self.show_text(spec, state) # {{{1
|
213
|
+
if spec['code']
|
214
|
+
eval spec, state do |v,n|
|
215
|
+
Eft.show_text _opts(spec, text: v) do |t|
|
216
|
+
t.on_ok { then_run n, state, spec['show_text'].to_sym => v }
|
217
|
+
on_cancel_esc t, spec, state
|
218
|
+
end
|
219
|
+
end
|
220
|
+
elsif spec['text']
|
221
|
+
Eft.show_text _opts(spec, text: spec['text']) do |t|
|
222
|
+
t.on_ok { then_run spec['then'], state }
|
223
|
+
on_cancel_esc t, spec, state
|
224
|
+
end
|
225
|
+
elsif spec['file']
|
226
|
+
Eft.show_text _opts(spec, file: spec['file']) do |t|
|
227
|
+
t.on_ok { then_run spec['then'], state }
|
228
|
+
on_cancel_esc t, spec, state
|
229
|
+
end
|
230
|
+
else
|
231
|
+
raise InvalidSpecError, 'show_text needs code, text, or file'
|
232
|
+
end
|
233
|
+
end # }}}1
|
234
|
+
|
235
|
+
# --
|
236
|
+
|
237
|
+
# turn ~/.eftcmdr.d into ~/.ssh/authorized_keys
|
238
|
+
def self.build_authorized_keys(file, dir) # {{{1
|
239
|
+
dir =~ %r{\A[A-Za-z0-9_./-]+\z} \
|
240
|
+
or raise InvalidFileNameError, "invalid dir name: #{dir}"
|
241
|
+
original = (File.exists?(file) ? File.read(file) : '') \
|
242
|
+
.lines.reject { |l| l =~ /EFTCMDR/ }
|
243
|
+
lines = Dir["#{dir}/*.pub"].sort.map do |x|
|
244
|
+
b = File.basename x, '.pub'
|
245
|
+
b =~ %r{\A[A-Za-z0-9_.-]+\z} \
|
246
|
+
or raise InvalidFileNameError, "invalid file name: #{x}"
|
247
|
+
k = File.read(x).chomp
|
248
|
+
f = File.exists?("#{dir}/#{b}.yml") ? "#{b}.yml" : 'default.yml'
|
249
|
+
SSH_LINE["eftcmdr #{dir}/#{f} #{b}", k, "(EFTCMDR #{x})"]
|
250
|
+
end
|
251
|
+
File.open(file, 'w') do |f|
|
252
|
+
(original + lines).each { |l| f.puts l }
|
253
|
+
end
|
254
|
+
end # }}}1
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
# vim: set tw=70 sw=2 sts=2 et fdm=marker :
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: eftcmdr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Felix C. Stegerman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: eft
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: obfusk-util
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.5.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.5.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: |
|
56
|
+
EftCmdr is a yaml dsl that wraps whiptail to display dialog boxes.
|
57
|
+
It provides a yaml dsl on top of eft. See examples/ for examples.
|
58
|
+
email:
|
59
|
+
- flx@obfusk.net
|
60
|
+
executables:
|
61
|
+
- eftcmdr
|
62
|
+
- eftcmdr-ssh-setup
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- ".yardopts"
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- eftcmdr.gemspec
|
70
|
+
- examples/hello.yml
|
71
|
+
- examples/qux.yml
|
72
|
+
- examples/bar.yml
|
73
|
+
- examples/foo.yml
|
74
|
+
- examples/foo.apps
|
75
|
+
- examples/bar.apps
|
76
|
+
- lib/eftcmdr.rb
|
77
|
+
- lib/eftcmdr/version.rb
|
78
|
+
- bin/eftcmdr
|
79
|
+
- bin/eftcmdr-ssh-setup
|
80
|
+
homepage: https://github.com/obfusk/eftcmdr
|
81
|
+
licenses:
|
82
|
+
- LGPLv3+
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 1.9.1
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.0.14
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: yaml + ruby + whiptail
|
104
|
+
test_files: []
|
105
|
+
has_rdoc:
|