tap-server 0.3.0 → 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.
- data/History +5 -0
- data/cmd/server.rb +36 -8
- data/lib/tap/controller/rest_routes.rb +77 -0
- data/lib/tap/controller/utils.rb +29 -0
- data/lib/tap/controller.rb +244 -145
- data/lib/tap/controllers/app.rb +97 -55
- data/lib/tap/controllers/data.rb +132 -0
- data/lib/tap/controllers/schema.rb +137 -223
- data/lib/tap/controllers/server.rb +70 -27
- data/lib/tap/server/data.rb +178 -0
- data/lib/tap/server/runner.rb +71 -0
- data/lib/tap/server/server_error.rb +35 -0
- data/lib/tap/server.rb +60 -275
- data/lib/tap/tasks/echo.rb +39 -6
- data/lib/tap/tasks/render.rb +65 -0
- data/public/stylesheets/tap.css +15 -2
- data/views/configurable/_config.erb +1 -0
- data/views/configurable/_configs.erb +28 -0
- data/views/configurable/_flag.erb +2 -0
- data/views/configurable/_list_select.erb +8 -0
- data/views/configurable/_select.erb +6 -0
- data/views/configurable/_switch.erb +2 -0
- data/views/layout.erb +1 -1
- data/views/object/obj.erb +1 -0
- data/views/tap/controllers/app/_action.erb +3 -0
- data/views/tap/controllers/app/build.erb +18 -0
- data/views/tap/controllers/app/enque.erb +13 -0
- data/views/tap/controllers/app/info.erb +20 -7
- data/views/tap/controllers/data/_controls.erb +21 -0
- data/views/tap/controllers/data/_index_entry.erb +1 -0
- data/views/tap/controllers/data/_upload.erb +8 -0
- data/views/tap/controllers/data/entry.erb +8 -0
- data/views/tap/controllers/data/index.erb +14 -0
- data/views/tap/controllers/schema/_build.erb +6 -0
- data/views/tap/controllers/schema/_index_entry.erb +6 -0
- data/views/tap/controllers/schema/entry.erb +135 -0
- data/views/tap/controllers/schema/join.erb +6 -4
- data/views/tap/controllers/schema/task.erb +6 -0
- data/views/tap/controllers/server/access.erb +4 -0
- data/views/tap/controllers/server/admin.erb +21 -0
- data/views/tap/controllers/server/help.erb +23 -0
- data/views/tap/controllers/server/index.erb +43 -3
- data/views/tap/task/input.erb +17 -0
- data/views/tap/tasks/load/input.erb +11 -0
- metadata +35 -17
- data/lib/tap/server_error.rb +0 -34
- data/lib/tap/support/persistence.rb +0 -71
- data/lib/tap/tasks/server.rb +0 -30
- data/views/tap/controllers/app/index.erb +0 -44
- data/views/tap/controllers/schema/config/default.erb +0 -4
- data/views/tap/controllers/schema/config/flag.erb +0 -3
- data/views/tap/controllers/schema/config/switch.erb +0 -6
- data/views/tap/controllers/schema/configurations.erb +0 -27
- data/views/tap/controllers/schema/node.erb +0 -47
- data/views/tap/controllers/schema/preview.erb +0 -3
- data/views/tap/controllers/schema/round.erb +0 -30
- data/views/tap/controllers/schema/schema.erb +0 -28
- data/views/tap/tasks/echo/result.html +0 -1
@@ -1,260 +1,174 @@
|
|
1
|
-
require 'tap/
|
1
|
+
require 'tap/controllers/data'
|
2
2
|
|
3
3
|
module Tap
|
4
4
|
module Controllers
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
set :default_layout, 'layout.erb'
|
9
|
-
|
10
|
-
# Initializes a new schema and redirects to display.
|
11
|
-
def index
|
12
|
-
id = initialize_schema
|
13
|
-
redirect("/schema/display/#{id}")
|
14
|
-
end
|
15
|
-
|
16
|
-
# Loads the schema indicated by id and renders 'schema.erb' with the default
|
17
|
-
# layout.
|
18
|
-
def display(id)
|
19
|
-
schema = load_schema(id)
|
20
|
-
render 'schema.erb', :locals => {
|
21
|
-
:id => id,
|
22
|
-
:schema => schema
|
23
|
-
}, :layout => true
|
24
|
-
end
|
25
|
-
|
26
|
-
# Updates the specified schema with the request parameters. Update forwards
|
27
|
-
# the request to the action ('add' or 'remove') specified in the action
|
28
|
-
# parameter.
|
29
|
-
def update(id)
|
30
|
-
case request['action']
|
31
|
-
when 'add' then add(id)
|
32
|
-
when 'remove' then remove(id)
|
33
|
-
when 'echo' then echo
|
34
|
-
else raise Tap::ServerError, "unknown action: #{request['action']}"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# Adds nodes or joins to the schema. Parameters:
|
39
|
-
#
|
40
|
-
# nodes[]:: An array of nodes to add to the schema. Each entry is split using
|
41
|
-
# Shellwords to yield an argv; the argv initializes the node. The
|
42
|
-
# index of each new node is added to targets[].
|
43
|
-
# sources[]:: An array of source node indicies used to create a join.
|
44
|
-
# targets[]:: An array of target node indicies used to create a join (note
|
45
|
-
# the indicies of new nodes are added to targets).
|
46
|
-
#
|
47
|
-
# Add creates and pushes new nodes onto schema as specified in nodes, then
|
48
|
-
# creates joins between the sources and targets. The join class is inferred
|
49
|
-
# by Utils.infer_join; if no join can be inferred the join class is
|
50
|
-
# effectively nil, and consistent with that, the node output for sources
|
51
|
-
# and the node input for targets is set to nil.
|
52
|
-
#
|
53
|
-
# === Notes
|
5
|
+
class Schema < Data
|
6
|
+
|
7
|
+
# Adds tasks or joins to the schema. Parameters:
|
54
8
|
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
9
|
+
# tasks[]:: An array of tasks to add to the schema.
|
10
|
+
# inputs[]:: An array of task indicies used as inputs to a join.
|
11
|
+
# outputs[]:: An array of task indicies used as outputs for a join.
|
58
12
|
#
|
59
13
|
def add(id)
|
60
|
-
|
61
|
-
|
14
|
+
if id == "new"
|
15
|
+
id = data.next_id(type).to_s
|
62
16
|
end
|
63
|
-
|
64
|
-
round = (request['round'] || 0).to_i
|
65
|
-
outputs = (request['outputs[]'] || []).collect {|index| index.to_i }
|
66
|
-
inputs = (request['inputs[]'] || []).collect {|index| index.to_i }
|
67
|
-
nodes = request['nodes[]'] || []
|
68
|
-
|
69
|
-
load_schema(id) do |schema|
|
70
|
-
nodes.each do |arg|
|
71
|
-
next unless arg && !arg.empty?
|
72
|
-
|
73
|
-
outputs << schema.nodes.length
|
74
|
-
schema.nodes << Tap::Support::Node.new(Shellwords.shellwords(arg), round)
|
75
|
-
end
|
76
|
-
|
77
|
-
if inputs.empty? || outputs.empty?
|
78
|
-
inputs.each {|index| schema[index].output = nil }
|
79
|
-
outputs.each {|index| schema[index].input = round }
|
80
|
-
else
|
81
17
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
18
|
+
tasks = request['tasks'] || []
|
19
|
+
inputs = request['inputs'] || []
|
20
|
+
outputs = request['outputs'] || []
|
21
|
+
queue = request['queue'] || []
|
86
22
|
|
87
|
-
|
23
|
+
update_schema(id) do |schema|
|
24
|
+
current = schema.tasks
|
25
|
+
tasks.each do |task|
|
26
|
+
key = task
|
27
|
+
while current.has_key?(key)
|
28
|
+
i ||= 0
|
29
|
+
key = "#{task}_#{i}"
|
30
|
+
i += 1
|
31
|
+
end
|
32
|
+
|
33
|
+
current[key] = {'id' => task}
|
34
|
+
end
|
35
|
+
|
36
|
+
if !inputs.empty? && !outputs.empty?
|
37
|
+
schema.joins << [inputs, outputs]
|
38
|
+
end
|
39
|
+
|
40
|
+
queue.each do |task|
|
41
|
+
schema.queue << [task]
|
88
42
|
end
|
89
43
|
end
|
90
|
-
|
91
|
-
redirect(
|
44
|
+
|
45
|
+
redirect uri(id)
|
92
46
|
end
|
93
|
-
|
94
|
-
# Removes
|
95
|
-
#
|
96
|
-
# sources[]:: An array of source node indicies to remove.
|
97
|
-
# targets[]:: An array of target node indicies to remove.
|
98
|
-
#
|
99
|
-
# Normally remove sets the node.output for each source to nil and the
|
100
|
-
# node.input for each target to nil. However, if a node is indicated in
|
101
|
-
# both sources and targets AND it has no join input/output, then it will
|
102
|
-
# be removed.
|
103
|
-
#
|
104
|
-
# === Notes
|
47
|
+
|
48
|
+
# Removes tasks or joins from a schema. Parameters:
|
105
49
|
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
# breaks the join '0:1' while 'sources[]=1' breaks the join '1:2'.
|
50
|
+
# tasks[]:: An array of task keys to remove.
|
51
|
+
# joins[]:: An array of join indicies to remove.
|
109
52
|
#
|
110
53
|
def remove(id)
|
111
|
-
|
112
|
-
|
54
|
+
if id == "new"
|
55
|
+
id = data.next_id(type).to_s
|
113
56
|
end
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
outputs.delete_if do |index|
|
123
|
-
next unless node = schema.nodes[index]
|
124
|
-
if node.input_join
|
125
|
-
node.input = round
|
126
|
-
true
|
127
|
-
else
|
128
|
-
false
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
inputs.delete_if do |index|
|
133
|
-
next unless node = schema.nodes[index]
|
134
|
-
if node.output_join
|
135
|
-
node.output = nil
|
136
|
-
true
|
137
|
-
else
|
138
|
-
false
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# Remove nodes. Setting a node to nil causes it's removal during
|
143
|
-
# compact; orphaned joins are removed during compact as well.
|
144
|
-
(inputs & outputs).each do |index|
|
145
|
-
schema.nodes[index] = nil
|
57
|
+
|
58
|
+
tasks = request['tasks'] || []
|
59
|
+
joins = request['joins'] || []
|
60
|
+
queue = request['queue'] || []
|
61
|
+
|
62
|
+
update_schema(id) do |schema|
|
63
|
+
tasks.each do |key|
|
64
|
+
schema.tasks.delete(key)
|
146
65
|
end
|
66
|
+
|
67
|
+
joins.each {|index| schema.joins[index.to_i] = nil }
|
68
|
+
schema.joins.compact!
|
69
|
+
|
70
|
+
queue.each {|index| schema.queue[index.to_i] = nil }
|
71
|
+
schema.queue.compact!
|
72
|
+
|
73
|
+
schema.cleanup!
|
147
74
|
end
|
148
75
|
|
149
|
-
redirect(
|
150
|
-
end
|
151
|
-
|
152
|
-
def submit(id)
|
153
|
-
case request['action']
|
154
|
-
when 'save' then save(id)
|
155
|
-
when 'preview' then preview(id)
|
156
|
-
when 'echo' then echo
|
157
|
-
when 'run'
|
158
|
-
dump_schema(id, schema)
|
159
|
-
run(id)
|
160
|
-
else raise Tap::ServerError, "unknown action: #{request['action']}"
|
161
|
-
end
|
76
|
+
redirect uri(id)
|
162
77
|
end
|
163
|
-
|
164
|
-
def
|
165
|
-
|
166
|
-
|
78
|
+
|
79
|
+
def configure(id)
|
80
|
+
if id == "new"
|
81
|
+
id = data.next_id(type).to_s
|
167
82
|
end
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
def preview(id)
|
174
|
-
response.headers['Content-Type'] = 'text/plain'
|
175
|
-
render('preview.erb', :locals => {:id => id, :schema => schema})
|
176
|
-
end
|
177
|
-
|
178
|
-
def run(id)
|
179
|
-
unless request.post?
|
180
|
-
raise Tap::ServerError, "run must be performed with post"
|
83
|
+
|
84
|
+
schema = Tap::Schema.new(request['schema'] || {})
|
85
|
+
schema.scrub! do |obj|
|
86
|
+
scrub(obj['config'])
|
181
87
|
end
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
tasks = server.env.tasks
|
186
|
-
schema.build(app) do |(key, *args)|
|
187
|
-
if const = tasks.search(key)
|
188
|
-
const.constantize.parse(args, app) do |help|
|
189
|
-
raise "help not implemented"
|
190
|
-
#redirect("/app/help/#{key}")
|
191
|
-
end
|
192
|
-
else
|
193
|
-
raise ArgumentError, "unknown task: #{key}"
|
194
|
-
end
|
88
|
+
|
89
|
+
data.create_or_update(type, id) do |io|
|
90
|
+
io << schema.dump
|
195
91
|
end
|
196
|
-
|
197
|
-
|
198
|
-
redirect("/app/tail")
|
92
|
+
|
93
|
+
redirect uri(id)
|
199
94
|
end
|
200
|
-
|
95
|
+
|
96
|
+
# Helper methods
|
201
97
|
protected
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
argv = request['argv[]'] || []
|
206
|
-
argv.delete_if {|arg| arg.empty? }
|
207
|
-
Tap::Support::Schema.parse(argv)
|
98
|
+
|
99
|
+
def env
|
100
|
+
server.env
|
208
101
|
end
|
209
|
-
|
210
|
-
def
|
211
|
-
|
212
|
-
|
213
|
-
id = random_key(current.length)
|
214
|
-
while current.include?(id)
|
215
|
-
id = random_key(current.length)
|
216
|
-
end
|
217
|
-
|
218
|
-
dump_schema(id, schema)
|
219
|
-
id
|
102
|
+
|
103
|
+
def type
|
104
|
+
:schema
|
220
105
|
end
|
221
|
-
|
222
|
-
def
|
223
|
-
|
224
|
-
|
225
|
-
end
|
226
|
-
schema = Tap::Support::Schema.load_file(path)
|
227
|
-
|
228
|
-
if block_given?
|
229
|
-
result = yield(schema)
|
230
|
-
dump_schema(id, schema)
|
231
|
-
result
|
106
|
+
|
107
|
+
def display(id)
|
108
|
+
schema = if path = data.find(type, id)
|
109
|
+
Tap::Schema.load_file(path)
|
232
110
|
else
|
233
|
-
|
111
|
+
Tap::Schema.new
|
234
112
|
end
|
113
|
+
|
114
|
+
schema.resolve! do |type, key, data|
|
115
|
+
env.manifest(type)[key]
|
116
|
+
end
|
117
|
+
|
118
|
+
render "entry.erb", :locals => {
|
119
|
+
:id => id,
|
120
|
+
:schema => schema
|
121
|
+
}, :layout => true
|
235
122
|
end
|
236
|
-
|
237
|
-
def
|
238
|
-
|
239
|
-
|
123
|
+
|
124
|
+
def stringify(obj)
|
125
|
+
case obj
|
126
|
+
when String, Numeric, true, false
|
127
|
+
obj.to_s
|
128
|
+
when Symbol, Regexp
|
129
|
+
obj.inspect
|
130
|
+
when nil
|
131
|
+
'~'
|
132
|
+
when $stdout
|
133
|
+
'data/results.txt'
|
134
|
+
else
|
135
|
+
obj
|
240
136
|
end
|
241
137
|
end
|
242
|
-
|
243
|
-
def
|
244
|
-
|
245
|
-
|
246
|
-
|
138
|
+
|
139
|
+
def default_config(configurable)
|
140
|
+
configs = configurable.configurations
|
141
|
+
Configurable::DelegateHash.new(configs).to_hash do |hash, key, value|
|
142
|
+
hash[key.to_s] = stringify(value)
|
143
|
+
end
|
247
144
|
end
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
145
|
+
|
146
|
+
def scrub(obj)
|
147
|
+
case obj
|
148
|
+
when Hash
|
149
|
+
obj.delete_if do |key, value|
|
150
|
+
value ? scrub(value) : true
|
151
|
+
end
|
152
|
+
when Array
|
153
|
+
obj.delete_if do |value|
|
154
|
+
value ? scrub(value) : true
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
false
|
252
159
|
end
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
160
|
+
|
161
|
+
def update_schema(id)
|
162
|
+
path = data.find(type, id) || data.create(type, id)
|
163
|
+
schema = Tap::Schema.load_file(path)
|
164
|
+
|
165
|
+
yield(schema)
|
166
|
+
|
167
|
+
data.update(type, id) do |io|
|
168
|
+
io << schema.dump
|
169
|
+
end
|
170
|
+
|
171
|
+
id
|
258
172
|
end
|
259
173
|
end
|
260
174
|
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'tap/controller'
|
2
|
+
require 'rack/mime'
|
3
|
+
require 'time'
|
2
4
|
|
3
5
|
module Tap
|
4
6
|
module Controllers
|
5
7
|
|
6
|
-
# :startdoc::controller remotely controls and
|
8
|
+
# :startdoc::controller remotely controls and monitor a server
|
7
9
|
#
|
8
10
|
# Server provides several uris to control and monitor the server behavior.
|
9
11
|
# Importantly, server allows the remote shutdown of a Tap::Server if a
|
@@ -11,48 +13,89 @@ module Tap
|
|
11
13
|
# background and still have a shutdown handle on them.
|
12
14
|
#
|
13
15
|
class Server < Tap::Controller
|
14
|
-
|
15
|
-
|
16
|
+
include Utils
|
17
|
+
|
16
18
|
def index
|
17
|
-
render
|
19
|
+
render('index.erb', :layout => true)
|
18
20
|
end
|
19
21
|
|
20
|
-
# Returns
|
22
|
+
# Returns pong
|
21
23
|
def ping
|
22
|
-
response['Content-Type'] =
|
24
|
+
response['Content-Type'] = "text/plain"
|
23
25
|
"pong"
|
24
26
|
end
|
25
27
|
|
26
|
-
#
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
# Essentially a login for server administration
|
29
|
+
def access
|
30
|
+
if request.get?
|
31
|
+
render 'access.erb', :locals => {
|
32
|
+
:secret => request['secret']
|
33
|
+
}, :layout => true
|
34
|
+
else
|
35
|
+
redirect uri("admin", :secret => request['secret'])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Administrate this server
|
40
|
+
def admin(secret=nil)
|
41
|
+
template = server.admin?(secret) ? 'admin.erb' : 'access.erb'
|
42
|
+
render template, :locals => {:secret => secret}, :layout => true
|
34
43
|
end
|
35
44
|
|
36
|
-
#
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
if
|
41
|
-
# wait a
|
42
|
-
Thread.new {sleep
|
45
|
+
# Terminates app and stops self (on post).
|
46
|
+
def shutdown(secret=nil)
|
47
|
+
response['Content-Type'] = "text/plain"
|
48
|
+
|
49
|
+
if server.admin?(secret) && request.post?
|
50
|
+
# wait a bit to shutdown, so the response is sent out.
|
51
|
+
Thread.new { sleep(0.1); server.stop! }
|
43
52
|
"shutdown"
|
44
53
|
else
|
45
|
-
"
|
54
|
+
""
|
46
55
|
end
|
47
56
|
end
|
48
57
|
|
49
|
-
|
58
|
+
def help(type=nil, *key)
|
59
|
+
if constant = server.env[type][key.join('/')]
|
60
|
+
module_render 'help.erb', constant
|
61
|
+
else
|
62
|
+
"unknown #{type}: #{key.join('/')}"
|
63
|
+
end
|
64
|
+
end
|
50
65
|
|
51
|
-
#
|
52
|
-
|
53
|
-
|
54
|
-
|
66
|
+
# ensure server methods are not added as actions
|
67
|
+
set :define_action, false
|
68
|
+
|
69
|
+
def call(rack_env)
|
70
|
+
path = rack_env['tap.server'].env.path(:public, rack_env['PATH_INFO']) {|file| File.file?(file) }
|
71
|
+
if path
|
72
|
+
static_file(path)
|
73
|
+
else
|
74
|
+
super
|
75
|
+
end
|
55
76
|
end
|
77
|
+
|
78
|
+
# Returns a controller uri, attaching the secret to the action, if specified.
|
79
|
+
def uri(action=nil, params={})
|
80
|
+
secret = params.delete(:secret)
|
81
|
+
|
82
|
+
if secret
|
83
|
+
action = action ? "#{action}/#{secret}" : secret
|
84
|
+
end
|
85
|
+
|
86
|
+
super(action, params)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns a help uri for the specified resource, currently only sketched out.
|
90
|
+
def help_uri(type, key)
|
91
|
+
uri("help/#{type}/#{key}")
|
92
|
+
end
|
93
|
+
|
94
|
+
# Stops the server.
|
95
|
+
def stop!
|
96
|
+
server.stop!
|
97
|
+
end
|
98
|
+
|
56
99
|
end
|
57
100
|
end
|
58
101
|
end
|