duty 0.1.0 → 0.2.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 +4 -4
- data/README.md +0 -1
- data/lib/duty/cli.rb +26 -171
- data/lib/duty/io/cli.rb +68 -0
- data/lib/duty/io.rb +6 -0
- data/lib/duty/plugins.rb +38 -20
- data/lib/duty/registry.rb +4 -4
- data/lib/duty/task_runner.rb +41 -0
- data/lib/duty/tasks.rb +3 -3
- data/lib/duty/version.rb +1 -1
- data/lib/duty/views/cli.rb +113 -0
- data/lib/duty/views.rb +6 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8859b7cf5b79a37d5fcb1fa2f23b05905b287b15
|
4
|
+
data.tar.gz: e338d56cb5912651b49f34217eed860b189820b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6923f6199cf0001806a1f3259feb89fd2fecdb9128319a92c299966528adc2393705eecb41101764936e6bd817e73366cc473fdd8183900a3d14d5ed392266e
|
7
|
+
data.tar.gz: afda6ff19cdca9f23cbfc7b2ea044163b9f6d7fd9931f3134e1c9af9fa386edf194a76348c5f3273936de8fdf40a6cc0593b003e750cf34da68f87afa6da974d
|
data/README.md
CHANGED
data/lib/duty/cli.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'duty/io'
|
1
2
|
require 'duty/registry'
|
2
3
|
require 'duty/plugins'
|
3
|
-
require 'duty/
|
4
|
+
require 'duty/task_runner'
|
5
|
+
require 'duty/views'
|
4
6
|
|
5
7
|
module Duty
|
6
8
|
class CLI
|
@@ -8,208 +10,61 @@ module Duty
|
|
8
10
|
attr_reader :registry
|
9
11
|
|
10
12
|
def initialize(args)
|
11
|
-
@input = Input.new(args)
|
12
|
-
@output = Output.new
|
13
|
-
@registry = Duty::Registry.load(
|
13
|
+
@input = Duty::IO::CLI::Input.new(args)
|
14
|
+
@output = Duty::IO::CLI::Output.new($stdout, $stderr)
|
15
|
+
@registry = Duty::Registry.register(Duty::Plugins.load(DUTY_CONFIG_FILENAME))
|
14
16
|
end
|
15
17
|
|
16
18
|
def exec
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
explain_duty if needs_help?
|
20
|
+
complete_task if needs_completion?
|
21
|
+
execute_task
|
20
22
|
end
|
21
23
|
|
22
24
|
private
|
23
25
|
|
24
26
|
attr_reader :input, :output
|
25
27
|
|
26
|
-
def
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
def stdout(string)
|
31
|
-
$stdout.puts string
|
28
|
+
def explain_duty
|
29
|
+
view.duty_explain
|
32
30
|
exit 0
|
33
31
|
end
|
34
32
|
|
35
|
-
def
|
36
|
-
input.
|
33
|
+
def needs_help?
|
34
|
+
input.needs_help?
|
37
35
|
end
|
38
36
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def completion?
|
44
|
-
input.completion?
|
37
|
+
def complete_task
|
38
|
+
view.task_complete
|
39
|
+
exit 0
|
45
40
|
end
|
46
41
|
|
47
|
-
def
|
48
|
-
|
42
|
+
def needs_completion?
|
43
|
+
input.needs_completion?
|
49
44
|
end
|
50
45
|
|
51
|
-
def
|
46
|
+
def execute_task
|
52
47
|
begin
|
53
|
-
|
54
|
-
rescue NameError =>
|
55
|
-
|
48
|
+
try_to_run_task
|
49
|
+
rescue NameError => error
|
50
|
+
view.task_invalid(error)
|
56
51
|
end
|
57
52
|
end
|
58
53
|
|
59
|
-
def
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
def invalid_task(error_message)
|
64
|
-
"duty: `#{input.join(' ')}` is not a duty task. Failed with: #{error_message}"
|
54
|
+
def try_to_run_task
|
55
|
+
Duty::TaskRunner.run(view, input, registry)
|
65
56
|
end
|
66
57
|
|
67
58
|
def view
|
68
59
|
if verbose?
|
69
|
-
|
60
|
+
Duty::Views::CLI::Verbose.new(self, input, output)
|
70
61
|
else
|
71
|
-
|
62
|
+
Duty::Views::CLI::Normal.new(self, input, output)
|
72
63
|
end
|
73
64
|
end
|
74
65
|
|
75
66
|
def verbose?
|
76
67
|
input.verbose?
|
77
68
|
end
|
78
|
-
|
79
|
-
class Input
|
80
|
-
def initialize(args)
|
81
|
-
@args = [args].flatten
|
82
|
-
end
|
83
|
-
|
84
|
-
def[](index)
|
85
|
-
@args[index]
|
86
|
-
end
|
87
|
-
|
88
|
-
def drop(index)
|
89
|
-
@args.drop(1)
|
90
|
-
end
|
91
|
-
|
92
|
-
def task_name
|
93
|
-
task, *rest = @args
|
94
|
-
task
|
95
|
-
end
|
96
|
-
|
97
|
-
def task_class
|
98
|
-
name = task_name.split('-').collect(&:capitalize).join
|
99
|
-
Object.const_get("Duty::Tasks::#{name}")
|
100
|
-
end
|
101
|
-
|
102
|
-
def task_input
|
103
|
-
task, *rest = @args
|
104
|
-
rest
|
105
|
-
end
|
106
|
-
|
107
|
-
def join(seperator='')
|
108
|
-
@args.join(seperator)
|
109
|
-
end
|
110
|
-
|
111
|
-
def verbose?
|
112
|
-
@args.include?('-v') || @args.include?('--verbose')
|
113
|
-
end
|
114
|
-
|
115
|
-
def completion?
|
116
|
-
@args.first == '--cmplt'
|
117
|
-
end
|
118
|
-
|
119
|
-
def help?
|
120
|
-
@args.empty? || @args == %w(-h) || @args == %w(--help)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
class Output
|
125
|
-
def print(*args)
|
126
|
-
$stdout.puts(*args)
|
127
|
-
end
|
128
|
-
|
129
|
-
def error(*args)
|
130
|
-
$stderr.puts(*args)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
class View
|
135
|
-
def initialize(output)
|
136
|
-
@output = output
|
137
|
-
end
|
138
|
-
|
139
|
-
def task_explain(task)
|
140
|
-
task_class = task.class
|
141
|
-
description = task_class.description
|
142
|
-
usage = task_class.usage
|
143
|
-
|
144
|
-
@output.print(description)
|
145
|
-
@output.print(usage)
|
146
|
-
end
|
147
|
-
|
148
|
-
def task_success(task)
|
149
|
-
task_name = task.class.name
|
150
|
-
success("#{task_name} task executed")
|
151
|
-
end
|
152
|
-
|
153
|
-
def task_failure(task)
|
154
|
-
task_name = task.class.name
|
155
|
-
failure("#{task_name} task aborted")
|
156
|
-
end
|
157
|
-
|
158
|
-
def command_success(command)
|
159
|
-
description = command.description
|
160
|
-
success(description)
|
161
|
-
end
|
162
|
-
|
163
|
-
def command_failure(command)
|
164
|
-
description = command.description
|
165
|
-
failure(description)
|
166
|
-
end
|
167
|
-
|
168
|
-
private
|
169
|
-
|
170
|
-
def success(msg)
|
171
|
-
@output.print([check_mark, msg].join(' '))
|
172
|
-
end
|
173
|
-
|
174
|
-
def failure(msg)
|
175
|
-
@output.error([cross_mark, msg].join(' '))
|
176
|
-
end
|
177
|
-
|
178
|
-
def cross_mark
|
179
|
-
unicode("2715")
|
180
|
-
end
|
181
|
-
|
182
|
-
def check_mark
|
183
|
-
unicode("2713")
|
184
|
-
end
|
185
|
-
|
186
|
-
def unicode(code)
|
187
|
-
["0x#{code}".hex].pack('U')
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
class VerboseView < View
|
192
|
-
def command_success(command)
|
193
|
-
success(command_msg(command))
|
194
|
-
end
|
195
|
-
|
196
|
-
def command_failure(command)
|
197
|
-
failure(command_msg(command))
|
198
|
-
end
|
199
|
-
|
200
|
-
private
|
201
|
-
|
202
|
-
def command_msg(command)
|
203
|
-
[command.description, command_logs(command)].join(' ')
|
204
|
-
end
|
205
|
-
|
206
|
-
def command_logs(command)
|
207
|
-
elements = command.logger.flatten
|
208
|
-
|
209
|
-
if elements.any?
|
210
|
-
["|>", elements.join(' | ')].join(' ')
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
69
|
end
|
215
70
|
end
|
data/lib/duty/io/cli.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
module Duty
|
2
|
+
module IO
|
3
|
+
module CLI
|
4
|
+
class Input
|
5
|
+
def initialize(args)
|
6
|
+
@args = [args].flatten
|
7
|
+
end
|
8
|
+
|
9
|
+
def[](index)
|
10
|
+
args[index]
|
11
|
+
end
|
12
|
+
|
13
|
+
def task_name
|
14
|
+
task, *rest = args
|
15
|
+
task
|
16
|
+
end
|
17
|
+
|
18
|
+
def task_input
|
19
|
+
task, *rest = args
|
20
|
+
rest
|
21
|
+
end
|
22
|
+
|
23
|
+
def drop(index)
|
24
|
+
args.drop(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
def join(seperator='')
|
28
|
+
args.join(seperator)
|
29
|
+
end
|
30
|
+
|
31
|
+
def verbose?
|
32
|
+
args.include?('-v') || args.include?('--verbose')
|
33
|
+
end
|
34
|
+
|
35
|
+
def needs_completion?
|
36
|
+
args.first == '--cmplt'
|
37
|
+
end
|
38
|
+
|
39
|
+
def needs_help?
|
40
|
+
args.empty? || args == %w(-h) || args == %w(--help)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
attr_reader :args
|
46
|
+
end
|
47
|
+
|
48
|
+
class Output
|
49
|
+
def initialize(stdout, stderr)
|
50
|
+
@stdout = stdout
|
51
|
+
@stderr = stderr
|
52
|
+
end
|
53
|
+
|
54
|
+
def print(*args)
|
55
|
+
stdout.puts(*args)
|
56
|
+
end
|
57
|
+
|
58
|
+
def error(*args)
|
59
|
+
stderr.puts(*args)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
attr_reader :stdout, :stderr
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/duty/io.rb
ADDED
data/lib/duty/plugins.rb
CHANGED
@@ -4,46 +4,64 @@ require 'yaml'
|
|
4
4
|
module Duty
|
5
5
|
module Plugins
|
6
6
|
def self.load(filename)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
Duty::Plugins::List.new.tap do |list|
|
8
|
+
if File.exists?(filename)
|
9
|
+
duty_config = YAML.load(File.read(filename))
|
10
|
+
tasks = duty_config["tasks"]
|
11
|
+
tasks.each do |namespace, plugin_entry_point|
|
12
|
+
list << Plugin.new(namespace, plugin_entry_point)
|
13
|
+
end
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
18
|
+
class List
|
19
|
+
require 'forwardable'
|
20
|
+
include Enumerable
|
21
|
+
extend Forwardable
|
22
|
+
def_delegators :@plugins, :each, :<<
|
23
|
+
def initialize
|
24
|
+
@plugins = []
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
16
28
|
class Plugin
|
17
|
-
|
18
|
-
def initialize(namespace, task_dir)
|
29
|
+
def initialize(namespace, entry)
|
19
30
|
@namespace = namespace
|
20
|
-
@
|
31
|
+
@entry = entry
|
32
|
+
@tasks = []
|
21
33
|
end
|
22
34
|
|
23
35
|
def namespace
|
24
36
|
@namespace
|
25
37
|
end
|
26
38
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
require path.gsub(/(\.rb)$/, '')
|
39
|
+
def tasks
|
40
|
+
@task_classes.select do |task_class|
|
41
|
+
valid?(task_class)
|
31
42
|
end
|
32
43
|
end
|
33
44
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
45
|
+
def load_tasks
|
46
|
+
require_tasks
|
47
|
+
expose_tasks
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def require_tasks
|
53
|
+
path = @entry.gsub(/\.rb/,'')
|
54
|
+
require path
|
55
|
+
end
|
56
|
+
|
57
|
+
def expose_tasks
|
58
|
+
@task_classes = eval(File.read(@entry)).tasks
|
41
59
|
end
|
42
60
|
|
43
61
|
private
|
44
62
|
|
45
63
|
def valid?(task_class)
|
46
|
-
task_class.
|
64
|
+
task_class.ancestors.include? ::Duty::Tasks::Base
|
47
65
|
end
|
48
66
|
end
|
49
67
|
end
|
data/lib/duty/registry.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Duty
|
2
2
|
class Registry
|
3
|
-
def self.
|
4
|
-
new(plugins).tap {|registry| registry.
|
3
|
+
def self.register(plugins = [])
|
4
|
+
new(plugins).tap {|registry| registry.load_tasks }
|
5
5
|
end
|
6
6
|
|
7
7
|
attr_reader :plugins
|
@@ -9,8 +9,8 @@ module Duty
|
|
9
9
|
@plugins = plugins
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
plugins.each {|plugin| plugin.
|
12
|
+
def load_tasks
|
13
|
+
plugins.each {|plugin| plugin.load_tasks }
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Duty
|
2
|
+
class TaskRunner
|
3
|
+
def initialize(view, input, registry)
|
4
|
+
@view = view
|
5
|
+
@input = input
|
6
|
+
@plugins = registry.plugins
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.run(view, input, plugins)
|
10
|
+
self.new(view, input, plugins).run
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
task_class.new(task_input, view).run
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :view
|
20
|
+
|
21
|
+
def task_class
|
22
|
+
name = task_name.split('-').collect(&:capitalize).join
|
23
|
+
@plugins.each do |plugin|
|
24
|
+
plugin.tasks.each do |task_class|
|
25
|
+
if task_class.to_s.split("::").last == name
|
26
|
+
@task_class = task_class
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@task_class
|
31
|
+
end
|
32
|
+
|
33
|
+
def task_input
|
34
|
+
@input.task_input
|
35
|
+
end
|
36
|
+
|
37
|
+
def task_name
|
38
|
+
@input.task_name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/duty/tasks.rb
CHANGED
@@ -35,9 +35,9 @@ module Duty
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def execute
|
38
|
-
ruby(
|
39
|
-
ruby(
|
40
|
-
ruby(
|
38
|
+
ruby('Describe your task') {}
|
39
|
+
ruby('Explain your task') {}
|
40
|
+
ruby('TODO: Implement your task by overwriting `execute`') { raise ExecutionError.new }
|
41
41
|
end
|
42
42
|
|
43
43
|
private
|
data/lib/duty/version.rb
CHANGED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'duty/meta'
|
2
|
+
|
3
|
+
module Duty
|
4
|
+
module Views
|
5
|
+
module CLI
|
6
|
+
class Normal
|
7
|
+
def initialize(cli, input, output)
|
8
|
+
@cli = cli
|
9
|
+
@input = input
|
10
|
+
@output = output
|
11
|
+
end
|
12
|
+
|
13
|
+
def duty_explain
|
14
|
+
output.print meta_help_message
|
15
|
+
end
|
16
|
+
|
17
|
+
def task_complete
|
18
|
+
output.print meta_completion_message
|
19
|
+
end
|
20
|
+
|
21
|
+
def task_explain(task)
|
22
|
+
task_class = task.class
|
23
|
+
description = task_class.description
|
24
|
+
usage = task_class.usage
|
25
|
+
|
26
|
+
output.print(description)
|
27
|
+
output.print(usage)
|
28
|
+
end
|
29
|
+
|
30
|
+
def task_success(task)
|
31
|
+
task_name = task.class.name
|
32
|
+
success("#{task_name} task executed")
|
33
|
+
end
|
34
|
+
|
35
|
+
def task_failure(task)
|
36
|
+
task_name = task.class.name
|
37
|
+
failure("#{task_name} task aborted")
|
38
|
+
end
|
39
|
+
|
40
|
+
def task_invalid(error)
|
41
|
+
error_message = "duty: `#{input.join(' ')}` is not a duty task. Failed with: #{error.message}"
|
42
|
+
output.print error_message
|
43
|
+
end
|
44
|
+
|
45
|
+
def command_success(command)
|
46
|
+
description = command.description
|
47
|
+
success(description)
|
48
|
+
end
|
49
|
+
|
50
|
+
def command_failure(command)
|
51
|
+
description = command.description
|
52
|
+
failure(description)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
attr_reader :cli, :input, :output
|
58
|
+
|
59
|
+
def success(msg)
|
60
|
+
output.print([check_mark, msg].join(' '))
|
61
|
+
end
|
62
|
+
|
63
|
+
def failure(msg)
|
64
|
+
output.error([cross_mark, msg].join(' '))
|
65
|
+
end
|
66
|
+
|
67
|
+
def cross_mark
|
68
|
+
unicode("2715")
|
69
|
+
end
|
70
|
+
|
71
|
+
def check_mark
|
72
|
+
unicode("2713")
|
73
|
+
end
|
74
|
+
|
75
|
+
def unicode(code)
|
76
|
+
["0x#{code}".hex].pack('U')
|
77
|
+
end
|
78
|
+
|
79
|
+
def meta_help_message
|
80
|
+
Duty::Meta::Help.new(cli).to_s
|
81
|
+
end
|
82
|
+
|
83
|
+
def meta_completion_message
|
84
|
+
Duty::Meta::Completion.new(cli, input.drop(1)).to_s
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Verbose < Normal
|
89
|
+
def command_success(command)
|
90
|
+
success(command_msg(command))
|
91
|
+
end
|
92
|
+
|
93
|
+
def command_failure(command)
|
94
|
+
failure(command_msg(command))
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def command_msg(command)
|
100
|
+
[command.description, command_logs(command)].join(' ')
|
101
|
+
end
|
102
|
+
|
103
|
+
def command_logs(command)
|
104
|
+
elements = command.logger.flatten
|
105
|
+
|
106
|
+
if elements.any?
|
107
|
+
["|>", elements.join(' | ')].join(' ')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/duty/views.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Owiesniak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -62,14 +62,19 @@ files:
|
|
62
62
|
- duty.gemspec
|
63
63
|
- lib/duty.rb
|
64
64
|
- lib/duty/cli.rb
|
65
|
+
- lib/duty/io.rb
|
66
|
+
- lib/duty/io/cli.rb
|
65
67
|
- lib/duty/meta.rb
|
66
68
|
- lib/duty/meta/completion.rb
|
67
69
|
- lib/duty/meta/help.rb
|
68
70
|
- lib/duty/meta/humanizer.rb
|
69
71
|
- lib/duty/plugins.rb
|
70
72
|
- lib/duty/registry.rb
|
73
|
+
- lib/duty/task_runner.rb
|
71
74
|
- lib/duty/tasks.rb
|
72
75
|
- lib/duty/version.rb
|
76
|
+
- lib/duty/views.rb
|
77
|
+
- lib/duty/views/cli.rb
|
73
78
|
homepage: https://github.com/JanOwiesniak/duty
|
74
79
|
licenses:
|
75
80
|
- MIT
|