shelldon 0.0.1 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +11 -0
- data/.rubocop.yml +60 -0
- data/Gemfile +0 -5
- data/README.md +0 -1
- data/lib/auto_complete.rb +34 -0
- data/lib/command/command.rb +63 -11
- data/lib/command/command_list.rb +16 -8
- data/lib/command/script.rb +33 -0
- data/lib/config/config.rb +13 -4
- data/lib/config/config_factory.rb +4 -0
- data/lib/config/param.rb +17 -11
- data/lib/config/param/boolean_param.rb +1 -1
- data/lib/config/param_factory.rb +6 -1
- data/lib/dsl.rb +17 -0
- data/lib/{Exceptions → exceptions}/error_factory.rb +10 -0
- data/lib/exceptions/exceptions.rb +60 -0
- data/lib/file_management/config_file_manager.rb +3 -7
- data/lib/file_management/history_file.rb +0 -2
- data/lib/file_management/yaml_manager.rb +10 -1
- data/lib/helpers/confirmation.rb +20 -0
- data/lib/helpers/timer.rb +5 -0
- data/lib/opts/opt_factory.rb +4 -3
- data/lib/opts/opts.rb +1 -1
- data/lib/shell/shell.rb +82 -19
- data/lib/shell/shell_factory.rb +87 -14
- data/lib/shell/shell_index.rb +11 -1
- data/lib/shelldon.rb +8 -3
- data/lib/shelldon/version.rb +1 -1
- data/shelldon.gemspec +15 -8
- data/test_shell/Gemfile +1 -2
- data/test_shell/Gemfile.lock +7 -6
- data/test_shell/dependency_test/Gemfile +2 -0
- data/test_shell/dependency_test/Gemfile.lock +21 -0
- data/test_shell/dependency_test/dependency_test.rb +20 -0
- data/test_shell/dependency_test/dt_commands.rb +66 -0
- data/test_shell/dependency_test/dt_config.rb +31 -0
- data/test_shell/dependency_test/dt_opts.rb +11 -0
- data/test_shell/dependency_test/dt_runner.rb +11 -0
- data/test_shell/simple_shell.rb +6 -6
- data/test_shell/test_shell.rb +46 -3
- data/test_shell/useful_commands.rb +1 -1
- metadata +80 -41
- data/Gemfile.lock +0 -43
@@ -10,7 +10,7 @@ module Shelldon
|
|
10
10
|
v
|
11
11
|
elsif v.is_a?(String)
|
12
12
|
return true if v == true || v =~ (/(true|t|yes|y|1)$/i)
|
13
|
-
return false if v == false || v
|
13
|
+
return false if v == false || v =~ (/(false|f|no|n|0)$/i)
|
14
14
|
fail(ArgumentError, "invalid value for Boolean: \"#{v}\"")
|
15
15
|
else
|
16
16
|
v ? true : false
|
data/lib/config/param_factory.rb
CHANGED
@@ -21,6 +21,10 @@ module Shelldon
|
|
21
21
|
@default = default_value
|
22
22
|
end
|
23
23
|
|
24
|
+
def override(value)
|
25
|
+
@override = value
|
26
|
+
end
|
27
|
+
|
24
28
|
def opt(opt)
|
25
29
|
@opt = opt
|
26
30
|
end
|
@@ -30,13 +34,14 @@ module Shelldon
|
|
30
34
|
if @param
|
31
35
|
@param.pretty = @pretty_proc if @pretty_proc
|
32
36
|
@param.default = @default unless @default.nil?
|
37
|
+
@param.override = @override if @override
|
33
38
|
@param.opt = @opt if @opt
|
34
39
|
@param.error = @error if @error
|
35
40
|
@param.validator = @validator if @validator
|
36
41
|
@param.adjustor = @adjustor if @adjustor
|
37
42
|
@config.register(@param)
|
38
43
|
else
|
39
|
-
fail
|
44
|
+
fail Shelldon::RegisterNilParamError
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
data/lib/dsl.rb
CHANGED
@@ -7,6 +7,10 @@ module Shelldon
|
|
7
7
|
ShellIndex.instance << shell if shell.is_a?(Shelldon::Shell)
|
8
8
|
end
|
9
9
|
|
10
|
+
def self.first?(sym)
|
11
|
+
ShellIndex.first?(sym)
|
12
|
+
end
|
13
|
+
|
10
14
|
def self.shell(name = (:default), &block)
|
11
15
|
ShellFactory.new(name.to_sym, &block)
|
12
16
|
end
|
@@ -18,4 +22,17 @@ module Shelldon
|
|
18
22
|
def self.opts
|
19
23
|
Shelldon::Opts.instance.opts
|
20
24
|
end
|
25
|
+
|
26
|
+
def self.method_missing(meth, *args, &block)
|
27
|
+
ShellIndex.instance[:default].send(meth, *args, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.confirm(*args)
|
31
|
+
Shelldon::Confirmation.ask(*args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.has_shell?(sym)
|
35
|
+
sym = sym.to_sym unless sym
|
36
|
+
ShellIndex.instance.key?(sym)
|
37
|
+
end
|
21
38
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Shelldon
|
2
2
|
class ErrorFactory
|
3
|
+
attr_reader :on_accept_error, :on_reject_error
|
4
|
+
|
3
5
|
def initialize(&block)
|
4
6
|
@accept_errors = {}
|
5
7
|
@reject_errors = {}
|
@@ -19,6 +21,14 @@ module Shelldon
|
|
19
21
|
@reject_errors[e] = (block_given? ? block : nil)
|
20
22
|
end
|
21
23
|
|
24
|
+
def on_accept(&block)
|
25
|
+
@on_accept_error = block
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_reject(&block)
|
29
|
+
@on_reject_error = block
|
30
|
+
end
|
31
|
+
|
22
32
|
def get
|
23
33
|
[@accept_errors, @reject_errors]
|
24
34
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Shelldon
|
2
|
+
class Error < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class ConfirmationError < Error
|
6
|
+
define_method(:message) { 'User did not provide a valid confirmation.' }
|
7
|
+
end
|
8
|
+
|
9
|
+
class NotImplementedError < Error
|
10
|
+
define_method(:message) { 'This command has not been implemented, or is a placeholder' }
|
11
|
+
end
|
12
|
+
|
13
|
+
class NoSuchCommandError < Error
|
14
|
+
define_method(:message) { 'No such command exists' }
|
15
|
+
end
|
16
|
+
|
17
|
+
class NotBooleanError < Error
|
18
|
+
define_method(:message) { 'The specified config param is not a boolean' }
|
19
|
+
end
|
20
|
+
|
21
|
+
class NotProcError < Error
|
22
|
+
define_method(:message) { 'Autocomplete must be a Proc or an Array' }
|
23
|
+
end
|
24
|
+
|
25
|
+
class DuplicateParamError < Error
|
26
|
+
define_method(:message) { 'Cannot create two params with the same name' }
|
27
|
+
end
|
28
|
+
|
29
|
+
class NoSuchParamError < Error
|
30
|
+
define_method(:message) { 'No such param exists' }
|
31
|
+
end
|
32
|
+
|
33
|
+
class InvalidParamValueError < Error
|
34
|
+
define_method(:message) { 'Param failed to pass validation' }
|
35
|
+
end
|
36
|
+
|
37
|
+
class RegisterNilParamError < Error
|
38
|
+
define_method(:message) { 'The Param Factory is attempting to register a nil.' }
|
39
|
+
end
|
40
|
+
|
41
|
+
class NoSuchOptTypeError < Error
|
42
|
+
define_method(:message) { 'The specified opt type was not :boolean or :required' }
|
43
|
+
end
|
44
|
+
|
45
|
+
class RedefineOptsError < Error
|
46
|
+
define_method(:message) { 'Cannot re-define opts' }
|
47
|
+
end
|
48
|
+
|
49
|
+
class NoSuchShellError < Error
|
50
|
+
define_method(:message) { 'The shell index does not contain that shell' }
|
51
|
+
end
|
52
|
+
|
53
|
+
class NotAShellError < Error
|
54
|
+
define_method(:message) { 'Cannot add non-shells to the shell index' }
|
55
|
+
end
|
56
|
+
|
57
|
+
class TimeoutError < Error
|
58
|
+
define_method(:message) { 'Operation timed out.' }
|
59
|
+
end
|
60
|
+
end
|
@@ -4,24 +4,20 @@ module Shelldon
|
|
4
4
|
class ConfigFileManager < YamlManager
|
5
5
|
def initialize(shell, config_file)
|
6
6
|
@shell = shell
|
7
|
-
@
|
7
|
+
@file = config_file
|
8
8
|
end
|
9
9
|
|
10
10
|
def ensure_dir(dir)
|
11
11
|
FileUtils.mkdir_p(dir)
|
12
12
|
end
|
13
13
|
|
14
|
-
def ensure_file(file)
|
15
|
-
File.open(file, 'w') { |f| f.write({}.to_yaml) } unless File.exist?(file)
|
16
|
-
end
|
17
|
-
|
18
14
|
def export
|
19
15
|
super(@shell.config)
|
20
16
|
end
|
21
17
|
|
22
18
|
def setup
|
23
|
-
@file = @
|
24
|
-
@file_dir = @
|
19
|
+
@file = @file.expand_path
|
20
|
+
@file_dir = @file.dirname.expand_path
|
25
21
|
ensure_dir(@file_dir)
|
26
22
|
ensure_file(@file)
|
27
23
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module Shelldon
|
3
2
|
class YamlManager < FileManager
|
4
3
|
def ensure_file(file)
|
@@ -10,7 +9,17 @@ module Shelldon
|
|
10
9
|
end
|
11
10
|
|
12
11
|
def import(_yaml)
|
12
|
+
reset unless valid?
|
13
13
|
YAML.load_file(@file)
|
14
14
|
end
|
15
|
+
|
16
|
+
def valid?
|
17
|
+
File.exist?(@file) && !File.zero?(@file)
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset
|
21
|
+
FileUtils.mv(@file, "#{@file}-#{Time.now.strftime('%y%m%d-%k%M%S')}.invalid")
|
22
|
+
ensure_file(@file)
|
23
|
+
end
|
15
24
|
end
|
16
25
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Shelldon
|
2
|
+
class Confirmation
|
3
|
+
def self.ask(*args)
|
4
|
+
new(*args).ask
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(msg = 'Confirm? (y/n)',
|
8
|
+
ok = %w(y Y yes Yes YES))
|
9
|
+
@msg = msg
|
10
|
+
@ok = ok
|
11
|
+
end
|
12
|
+
|
13
|
+
def ask
|
14
|
+
puts @msg
|
15
|
+
print '> '
|
16
|
+
response = $stdin.gets.chomp
|
17
|
+
@ok.include?(response) ? true : fail(Shelldon::ConfirmationError)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/helpers/timer.rb
CHANGED
data/lib/opts/opt_factory.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Shelldon
|
2
2
|
class OptFactory
|
3
|
-
def initialize(&block)
|
3
|
+
def initialize(name, &block)
|
4
|
+
@name = name
|
4
5
|
@opt_arr = []
|
5
6
|
instance_eval(&block)
|
6
|
-
Shelldon.opts = get_opts
|
7
|
+
Shelldon.opts = get_opts if Shelldon.first?(@name)
|
7
8
|
end
|
8
9
|
|
9
10
|
def get_opts
|
@@ -23,7 +24,7 @@ module Shelldon
|
|
23
24
|
when :required
|
24
25
|
Getopt::REQUIRED
|
25
26
|
else
|
26
|
-
fail
|
27
|
+
fail Shelldon::NoSuchOptTypeError
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
data/lib/opts/opts.rb
CHANGED
data/lib/shell/shell.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
require 'byebug'
|
2
1
|
require 'readline'
|
2
|
+
require_relative '../auto_complete'
|
3
|
+
# require 'byebug'
|
3
4
|
|
4
5
|
module Shelldon
|
5
6
|
class Shell
|
6
|
-
attr_accessor :command_list, :config,
|
7
|
-
|
8
|
-
attr_reader :home, :name
|
7
|
+
attr_accessor :command_list, :config, :accept_errors, :reject_errors, :on_opts, :on_pipe
|
8
|
+
attr_reader :home, :name, :config, :logger
|
9
9
|
attr_writer :history, :history_file
|
10
10
|
|
11
11
|
def initialize(name, &block)
|
@@ -15,25 +15,39 @@ module Shelldon
|
|
15
15
|
@errors = {}
|
16
16
|
@history = true
|
17
17
|
@command_list = CommandList.new(self)
|
18
|
-
@config = Config.new(self)
|
18
|
+
@config = Shelldon::Config.new(self)
|
19
|
+
@autocomplete = Shelldon::AutoComplete.new(self) # if defined?(Shelldon::AutoComplete)
|
20
|
+
@on_opts = {}
|
19
21
|
setup(&block) if block_given?
|
20
22
|
end
|
21
23
|
|
24
|
+
def shell
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
22
28
|
def self.method_missing(meth_name, *args, &block)
|
23
29
|
Shelldon::ShellIndex[:default].send(meth_name, *args, &block)
|
24
30
|
end
|
25
31
|
|
32
|
+
def self.[](key)
|
33
|
+
fail Shelldon::NoSuchShellError unless Shelldon::ShellIndex[key]
|
34
|
+
Shelldon::ShellIndex[key]
|
35
|
+
end
|
36
|
+
|
26
37
|
def setup(&block)
|
27
38
|
instance_eval(&block)
|
28
|
-
FileUtils.mkdir_p(@home.to_s) unless File.exist?(@home)
|
39
|
+
FileUtils.mkdir_p(@home.to_s) unless File.exist?(@home) if @home
|
29
40
|
Dir.chdir(@home) if @home
|
30
|
-
|
41
|
+
if @auto_complete_proc
|
42
|
+
Readline.completion_proc = @auto_complete_proc
|
43
|
+
else
|
44
|
+
@autocomplete.set_proc if @autocomplete
|
45
|
+
end
|
46
|
+
|
31
47
|
if @history_path && @history
|
32
48
|
@history_helper = Shelldon::HistoryFile.new(@history_path)
|
33
|
-
@history_helper.load if @history_helper
|
34
49
|
end
|
35
50
|
@config.load_config_file
|
36
|
-
run
|
37
51
|
end
|
38
52
|
|
39
53
|
def quit
|
@@ -42,35 +56,65 @@ module Shelldon
|
|
42
56
|
exit 0
|
43
57
|
end
|
44
58
|
|
59
|
+
def run_opt_conditions
|
60
|
+
@on_opts.each do |opt, procs|
|
61
|
+
if Shelldon.opts && Shelldon.opts.key?(opt)
|
62
|
+
procs.each do |proc|
|
63
|
+
instance_eval(&proc)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_piped_input
|
70
|
+
return if $stdin.tty?
|
71
|
+
if @on_pipe
|
72
|
+
instance_exec($stdin.readlines, &@on_pipe)
|
73
|
+
else
|
74
|
+
$stdin.readlines.each { |cmd| run_commands(cmd) }
|
75
|
+
end
|
76
|
+
exit 0
|
77
|
+
end
|
78
|
+
|
45
79
|
def run
|
80
|
+
@history_helper.load
|
81
|
+
run_opt_conditions
|
82
|
+
handle_piped_input
|
46
83
|
instance_eval(&@startup) if @startup
|
47
84
|
begin
|
48
85
|
run_repl
|
49
86
|
rescue *@accept_errors.keys => e
|
50
87
|
print_error(e)
|
51
|
-
|
88
|
+
@logger.warn(e)
|
89
|
+
on_error(e, @accept_errors[e.class], :accept)
|
52
90
|
retry
|
53
91
|
rescue *@reject_errors.keys => e
|
54
92
|
print_error(e)
|
55
|
-
|
93
|
+
@logger.fatal(e)
|
94
|
+
on_error(e, @reject_errors[e.class], :reject)
|
56
95
|
rescue StandardError => e
|
57
96
|
print_error(e)
|
58
97
|
puts "Reached fatal error. G'bye!"
|
59
|
-
raise e
|
60
98
|
ensure
|
99
|
+
# puts "Last exception: #{$!.inspect}" #if @config[:debug_mode]
|
100
|
+
# puts "Last backtrace: \n#{$@.join("\n")}"# if @config[:debug_mode]
|
61
101
|
instance_eval(&@shutdown) if @shutdown
|
62
102
|
@history_helper.save if @history_helper
|
63
103
|
quit
|
64
104
|
end
|
65
105
|
end
|
66
106
|
|
67
|
-
def on_error(e, proc)
|
68
|
-
|
107
|
+
def on_error(e, proc, type = nil)
|
108
|
+
run_accept_error(e) if type == :accept
|
109
|
+
run_reject_error(e) if type == :reject
|
110
|
+
instance_exec(e, &proc) if proc
|
69
111
|
end
|
70
112
|
|
71
113
|
def print_error(e)
|
72
|
-
return
|
73
|
-
puts e.
|
114
|
+
return unless @config[:debug_mode]
|
115
|
+
puts "Hit Error! (#{e.class})"
|
116
|
+
msg = (e.message == e.class.to_s ? '' : "(#{e.message})")
|
117
|
+
puts msg unless msg == '()'
|
74
118
|
puts e.backtrace.join("\n")
|
75
119
|
end
|
76
120
|
|
@@ -101,7 +145,7 @@ module Shelldon
|
|
101
145
|
end
|
102
146
|
|
103
147
|
def run_command(cmd)
|
104
|
-
@history_helper << cmd
|
148
|
+
@history_helper << cmd if @history_helper
|
105
149
|
run_precommand(cmd)
|
106
150
|
@command_list.run(cmd)
|
107
151
|
run_postcommand(cmd)
|
@@ -115,6 +159,14 @@ module Shelldon
|
|
115
159
|
instance_exec(cmd, &@post_command) if @post_command
|
116
160
|
end
|
117
161
|
|
162
|
+
def run_accept_error(error)
|
163
|
+
instance_exec(error, &@on_accept_error) if @on_accept_error
|
164
|
+
end
|
165
|
+
|
166
|
+
def run_reject_error(error)
|
167
|
+
instance_exec(error, &@on_reject_error) if @on_reject_error
|
168
|
+
end
|
169
|
+
|
118
170
|
def init(&block)
|
119
171
|
instance_eval(&block)
|
120
172
|
end
|
@@ -131,6 +183,11 @@ module Shelldon
|
|
131
183
|
@history_path = file
|
132
184
|
end
|
133
185
|
|
186
|
+
def log_file(filepath, freq = 'daily')
|
187
|
+
filepath = Pathname.new(filepath).expand_path.to_s
|
188
|
+
@logger = Logger.new(filepath, freq)
|
189
|
+
end
|
190
|
+
|
134
191
|
def prompt(str = '> ', &block)
|
135
192
|
if block_given?
|
136
193
|
@prompt_setter = block
|
@@ -160,8 +217,14 @@ module Shelldon
|
|
160
217
|
end
|
161
218
|
|
162
219
|
def errors(&block)
|
163
|
-
|
164
|
-
|
220
|
+
error_factory = Shelldon::ErrorFactory.new(&block)
|
221
|
+
@accept_errors, @reject_errors = error_factory.get
|
222
|
+
@on_accept_error = error_factory.on_accept_error
|
223
|
+
@on_reject_error = error_factory.on_reject_error
|
224
|
+
end
|
225
|
+
|
226
|
+
def autocomplete(&block)
|
227
|
+
@auto_complete_proc = block.to_proc
|
165
228
|
end
|
166
229
|
end
|
167
230
|
end
|