tap-server 0.1.1 → 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.
- data/History +4 -0
- data/README +1 -1
- data/lib/tap/controllers/app.rb +98 -0
- data/lib/tap/controllers/schema.rb +261 -0
- data/lib/tap/server.rb +14 -14
- data/views/{app_controller → tap/controllers/app}/index.erb +0 -0
- data/views/{app_controller → tap/controllers/app}/info.erb +0 -0
- data/views/{app_controller → tap/controllers/app}/tail.erb +0 -0
- data/views/{schema_controller → tap/controllers/schema}/config/default.erb +0 -0
- data/views/{schema_controller → tap/controllers/schema}/config/flag.erb +0 -0
- data/views/{schema_controller → tap/controllers/schema}/config/switch.erb +0 -0
- data/views/{schema_controller → tap/controllers/schema}/configurations.erb +0 -0
- data/views/{schema_controller → tap/controllers/schema}/join.erb +0 -0
- data/views/{schema_controller → tap/controllers/schema}/node.erb +0 -0
- data/views/{schema_controller → tap/controllers/schema}/preview.erb +0 -0
- data/views/{schema_controller → tap/controllers/schema}/round.erb +0 -0
- data/views/{schema_controller → tap/controllers/schema}/schema.erb +0 -0
- metadata +17 -17
- data/controllers/app_controller.rb +0 -92
- data/controllers/schema_controller.rb +0 -255
data/History
CHANGED
data/README
CHANGED
@@ -45,5 +45,5 @@ Tap requires an updated version of RubyGems[http://docs.rubygems.org/]
|
|
45
45
|
Copyright (c) 2009, Regents of the University of Colorado.
|
46
46
|
Developer:: {Simon Chiang}[http://bahuvrihi.wordpress.com], {Biomolecular Structure Program}[http://biomol.uchsc.edu/], {Hansen Lab}[http://hsc-proteomics.uchsc.edu/hansenlab/]
|
47
47
|
Support:: CU Denver School of Medicine Deans Academic Enrichment Fund
|
48
|
-
|
48
|
+
License:: {MIT-Style}[link:files/MIT-LICENSE.html]
|
49
49
|
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'tap/controller'
|
2
|
+
require 'rack/mime'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
module Tap
|
6
|
+
module Controllers
|
7
|
+
|
8
|
+
# ::controller
|
9
|
+
class App < Tap::Controller
|
10
|
+
set :default_layout, 'layout.erb'
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
# serve public files before actions
|
14
|
+
server = env['tap.server'] ||= Tap::Server.new
|
15
|
+
|
16
|
+
if path = server.public_path(env['PATH_INFO'])
|
17
|
+
content = File.read(path)
|
18
|
+
headers = {
|
19
|
+
"Last-Modified" => [File.mtime(path).httpdate],
|
20
|
+
"Content-Type" => [Rack::Mime.mime_type(File.extname(path), 'text/plain')],
|
21
|
+
"Content-Length" => [content.size.to_s]
|
22
|
+
}
|
23
|
+
|
24
|
+
[200, headers, [content]]
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def index
|
31
|
+
env_names = {}
|
32
|
+
server.env.minimap.each do |name, environment|
|
33
|
+
env_names[environment] = name
|
34
|
+
end
|
35
|
+
|
36
|
+
render('index.erb', :locals => {:env => server.env, :env_names => env_names}, :layout => true)
|
37
|
+
end
|
38
|
+
|
39
|
+
def info
|
40
|
+
if request.post?
|
41
|
+
app.info
|
42
|
+
else
|
43
|
+
render('info.erb', :locals => {:update => true, :content => app.info}, :layout => true)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
#--
|
48
|
+
# Currently tail is hard-coded to tail the server log only.
|
49
|
+
def tail(id=nil)
|
50
|
+
begin
|
51
|
+
path = root.subpath(:log, 'server.log')
|
52
|
+
raise unless File.exists?(path)
|
53
|
+
rescue
|
54
|
+
raise Tap::ServerError.new("invalid path", 404)
|
55
|
+
end
|
56
|
+
|
57
|
+
pos = request['pos'].to_i
|
58
|
+
if pos > File.size(path)
|
59
|
+
raise Tap::ServerError.new("tail position out of range (try update)", 500)
|
60
|
+
end
|
61
|
+
|
62
|
+
content = File.open(path) do |file|
|
63
|
+
file.pos = pos
|
64
|
+
file.read
|
65
|
+
end
|
66
|
+
|
67
|
+
if request.post?
|
68
|
+
content
|
69
|
+
else
|
70
|
+
render('tail.erb', :locals => {
|
71
|
+
:id => id,
|
72
|
+
:path => File.basename(path),
|
73
|
+
:update => true,
|
74
|
+
:content => content
|
75
|
+
}, :layout => true)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def run
|
80
|
+
Thread.new { app.run }
|
81
|
+
redirect("/app/tail")
|
82
|
+
end
|
83
|
+
|
84
|
+
def stop
|
85
|
+
app.stop
|
86
|
+
redirect("/app/info")
|
87
|
+
end
|
88
|
+
|
89
|
+
def terminate
|
90
|
+
app.terminate
|
91
|
+
redirect("/app/info")
|
92
|
+
end
|
93
|
+
|
94
|
+
def help(key=nil)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,261 @@
|
|
1
|
+
require 'tap/controller'
|
2
|
+
|
3
|
+
module Tap
|
4
|
+
module Controllers
|
5
|
+
|
6
|
+
# ::controller
|
7
|
+
class Schema < Tap::Controller
|
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
|
54
|
+
#
|
55
|
+
# The nomenclature for source and target is relative to the join, and may
|
56
|
+
# seem backwards for the node (ex: 'sources[]=0&targets[]=1' makes a join
|
57
|
+
# like '0:1')
|
58
|
+
#
|
59
|
+
def add(id)
|
60
|
+
unless request.post?
|
61
|
+
raise Tap::ServerError, "add must be performed with post"
|
62
|
+
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
|
+
|
82
|
+
# temporary
|
83
|
+
if inputs.length > 1 && outputs.length > 1
|
84
|
+
raise "multi-way join specified"
|
85
|
+
end
|
86
|
+
|
87
|
+
schema.set(Tap::Support::Join, inputs, outputs)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
redirect("/schema/display/#{id}")
|
92
|
+
end
|
93
|
+
|
94
|
+
# Removes nodes or joins from the schema. Parameters:
|
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
|
105
|
+
#
|
106
|
+
# The nomenclature for source and target is relative to the join, and may
|
107
|
+
# seem backwards for the node (ex: for the sequence '0:1:2', 'targets[]=1'
|
108
|
+
# breaks the join '0:1' while 'sources[]=1' breaks the join '1:2'.
|
109
|
+
#
|
110
|
+
def remove(id)
|
111
|
+
unless request.post?
|
112
|
+
raise Tap::ServerError, "remove must be performed with post"
|
113
|
+
end
|
114
|
+
|
115
|
+
round = (request['round'] || 0).to_i
|
116
|
+
outputs = (request['outputs[]'] || []).collect {|index| index.to_i }
|
117
|
+
inputs = (request['inputs[]'] || []).collect {|index| index.to_i }
|
118
|
+
|
119
|
+
load_schema(id) do |schema|
|
120
|
+
# Remove joins. Removed indicies are popped to ensure
|
121
|
+
# that if a join was removed the node will not be.
|
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
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
redirect("/schema/display/#{id}")
|
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
|
162
|
+
end
|
163
|
+
|
164
|
+
def save(id)
|
165
|
+
unless request.post?
|
166
|
+
raise Tap::ServerError, "submit must be performed with post"
|
167
|
+
end
|
168
|
+
|
169
|
+
dump_schema(id, schema)
|
170
|
+
redirect("/schema/display/#{id}")
|
171
|
+
end
|
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"
|
181
|
+
end
|
182
|
+
|
183
|
+
# it would be nice to someday put all this on a separate thread...
|
184
|
+
schema = load_schema(id)
|
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
|
195
|
+
end
|
196
|
+
|
197
|
+
Thread.new { app.run }
|
198
|
+
redirect("/app/tail")
|
199
|
+
end
|
200
|
+
|
201
|
+
protected
|
202
|
+
|
203
|
+
# Parses a Tap::Support::Schema from the request.
|
204
|
+
def schema
|
205
|
+
argv = request['argv[]'] || []
|
206
|
+
argv.delete_if {|arg| arg.empty? }
|
207
|
+
Tap::Support::Schema.parse(argv)
|
208
|
+
end
|
209
|
+
|
210
|
+
def initialize_schema
|
211
|
+
current = root.glob(:schema, "*").collect {|path| File.basename(path).chomp(".yml") }
|
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
|
220
|
+
end
|
221
|
+
|
222
|
+
def load_schema(id)
|
223
|
+
unless path = root.filepath(:schema, "#{id}.yml")
|
224
|
+
raise ServerError, "no schema for id: #{id}"
|
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
|
232
|
+
else
|
233
|
+
schema
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def dump_schema(id, schema=nil)
|
238
|
+
root.prepare(:schema, "#{id}.yml") do |file|
|
239
|
+
file << YAML.dump(schema.dump) if schema
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def instantiate(*argv)
|
244
|
+
key = argv.shift
|
245
|
+
tasc = server.env.tasks.search(key).constantize
|
246
|
+
tasc.parse(argv)
|
247
|
+
end
|
248
|
+
|
249
|
+
# helper to echo requests back... good for debugging
|
250
|
+
def echo # :nodoc:
|
251
|
+
"<pre>#{request.params.to_yaml}</pre>"
|
252
|
+
end
|
253
|
+
|
254
|
+
# Generates a random integer key.
|
255
|
+
def random_key(length) # :nodoc:
|
256
|
+
length = 1 if length < 1
|
257
|
+
rand(length * 10000).to_s
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
data/lib/tap/server.rb
CHANGED
@@ -6,16 +6,14 @@ require 'tap/server_error'
|
|
6
6
|
|
7
7
|
module Tap
|
8
8
|
Env.manifest(:controllers) do |env|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
Support::Manifest.intern(entries) do |manifest, const|
|
15
|
-
const.basename.chomp('_controller')
|
9
|
+
controllers = Support::ConstantManifest.new('controller')
|
10
|
+
env.load_paths.each do |path_root|
|
11
|
+
controllers.register(path_root, '**/*.rb')
|
16
12
|
end
|
13
|
+
controllers
|
17
14
|
end
|
18
15
|
|
16
|
+
# :::-
|
19
17
|
# Server is a Rack application that dispatches calls to other Rack apps, most
|
20
18
|
# commonly a Tap::Controller.
|
21
19
|
#
|
@@ -37,24 +35,25 @@ module Tap
|
|
37
35
|
# req.get('/sample/path/to/resource').body # => "Sample got /sample : /path/to/resource"
|
38
36
|
#
|
39
37
|
# Server automatically maps unknown keys to a controller by searching
|
40
|
-
# env.controllers. As a result '/example' maps to the
|
41
|
-
# defined in '
|
38
|
+
# env.controllers. As a result '/example' maps to the Example controller
|
39
|
+
# defined in 'lib/example.rb'.
|
42
40
|
#
|
43
|
-
# # [
|
44
|
-
# #
|
41
|
+
# # [lib/example.rb] => %q{
|
42
|
+
# # ::controller
|
43
|
+
# # class Example
|
45
44
|
# # def self.call(env)
|
46
|
-
# # [200, {}, ["
|
45
|
+
# # [200, {}, ["Example got #{env['SCRIPT_NAME']} : #{env['PATH_INFO']}"]]
|
47
46
|
# # end
|
48
47
|
# # end
|
49
48
|
# # }
|
50
49
|
#
|
51
|
-
# req.get('/example/path/to/resource').body # => "
|
50
|
+
# req.get('/example/path/to/resource').body # => "Example got /example : /path/to/resource"
|
52
51
|
#
|
53
52
|
# If desired, controllers can be set with aliases to map a path key to a
|
54
53
|
# lookup key.
|
55
54
|
#
|
56
55
|
# server.controllers['sample'] = 'example'
|
57
|
-
# req.get('/sample/path/to/resource').body # => "
|
56
|
+
# req.get('/sample/path/to/resource').body # => "Example got /sample : /path/to/resource"
|
58
57
|
#
|
59
58
|
# If no controller can be found, the request is routed using the
|
60
59
|
# default_controller_key and the request is NOT adjusted.
|
@@ -66,6 +65,7 @@ module Tap
|
|
66
65
|
#
|
67
66
|
# req.get('/unknown/path/to/resource').body # => "App got : /unknown/path/to/resource"
|
68
67
|
#
|
68
|
+
# :::+
|
69
69
|
class Server
|
70
70
|
include Rack::Utils
|
71
71
|
include Configurable
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tap-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon Chiang
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-03-07 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.12.
|
23
|
+
version: 0.12.3
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rack
|
@@ -44,9 +44,9 @@ extra_rdoc_files:
|
|
44
44
|
- History
|
45
45
|
files:
|
46
46
|
- cmd/server.rb
|
47
|
-
- controllers/app_controller.rb
|
48
|
-
- controllers/schema_controller.rb
|
49
47
|
- lib/tap/controller.rb
|
48
|
+
- lib/tap/controllers/app.rb
|
49
|
+
- lib/tap/controllers/schema.rb
|
50
50
|
- lib/tap/server.rb
|
51
51
|
- lib/tap/server_error.rb
|
52
52
|
- lib/tap/tasks/echo.rb
|
@@ -57,19 +57,19 @@ files:
|
|
57
57
|
- tap.yml
|
58
58
|
- views/404.erb
|
59
59
|
- views/500.erb
|
60
|
-
- views/app_controller/index.erb
|
61
|
-
- views/app_controller/info.erb
|
62
|
-
- views/app_controller/tail.erb
|
63
60
|
- views/layout.erb
|
64
|
-
- views/
|
65
|
-
- views/
|
66
|
-
- views/
|
67
|
-
- views/
|
68
|
-
- views/
|
69
|
-
- views/
|
70
|
-
- views/
|
71
|
-
- views/
|
72
|
-
- views/
|
61
|
+
- views/tap/controllers/app/index.erb
|
62
|
+
- views/tap/controllers/app/info.erb
|
63
|
+
- views/tap/controllers/app/tail.erb
|
64
|
+
- views/tap/controllers/schema/config/default.erb
|
65
|
+
- views/tap/controllers/schema/config/flag.erb
|
66
|
+
- views/tap/controllers/schema/config/switch.erb
|
67
|
+
- views/tap/controllers/schema/configurations.erb
|
68
|
+
- views/tap/controllers/schema/join.erb
|
69
|
+
- views/tap/controllers/schema/node.erb
|
70
|
+
- views/tap/controllers/schema/preview.erb
|
71
|
+
- views/tap/controllers/schema/round.erb
|
72
|
+
- views/tap/controllers/schema/schema.erb
|
73
73
|
- views/tap/tasks/echo/result.html
|
74
74
|
- README
|
75
75
|
- MIT-LICENSE
|
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'tap/controller'
|
2
|
-
require 'rack/mime'
|
3
|
-
require 'time'
|
4
|
-
|
5
|
-
class AppController < Tap::Controller
|
6
|
-
set :default_layout, 'layout.erb'
|
7
|
-
|
8
|
-
def call(env)
|
9
|
-
# serve public files before actions
|
10
|
-
server = env['tap.server'] ||= Tap::Server.new
|
11
|
-
|
12
|
-
if path = server.public_path(env['PATH_INFO'])
|
13
|
-
content = File.read(path)
|
14
|
-
headers = {
|
15
|
-
"Last-Modified" => [File.mtime(path).httpdate],
|
16
|
-
"Content-Type" => [Rack::Mime.mime_type(File.extname(path), 'text/plain')],
|
17
|
-
"Content-Length" => [content.size.to_s]
|
18
|
-
}
|
19
|
-
|
20
|
-
[200, headers, [content]]
|
21
|
-
else
|
22
|
-
super
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def index
|
27
|
-
env_names = {}
|
28
|
-
server.env.minimap.each do |name, environment|
|
29
|
-
env_names[environment] = name
|
30
|
-
end
|
31
|
-
|
32
|
-
render('index.erb', :locals => {:env => server.env, :env_names => env_names}, :layout => true)
|
33
|
-
end
|
34
|
-
|
35
|
-
def info
|
36
|
-
if request.post?
|
37
|
-
app.info
|
38
|
-
else
|
39
|
-
render('info.erb', :locals => {:update => true, :content => app.info}, :layout => true)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
#--
|
44
|
-
# Currently tail is hard-coded to tail the server log only.
|
45
|
-
def tail(id=nil)
|
46
|
-
begin
|
47
|
-
path = root.subpath(:log, 'server.log')
|
48
|
-
raise unless File.exists?(path)
|
49
|
-
rescue
|
50
|
-
raise Tap::ServerError.new("invalid path", 404)
|
51
|
-
end
|
52
|
-
|
53
|
-
pos = request['pos'].to_i
|
54
|
-
if pos > File.size(path)
|
55
|
-
raise Tap::ServerError.new("tail position out of range (try update)", 500)
|
56
|
-
end
|
57
|
-
|
58
|
-
content = File.open(path) do |file|
|
59
|
-
file.pos = pos
|
60
|
-
file.read
|
61
|
-
end
|
62
|
-
|
63
|
-
if request.post?
|
64
|
-
content
|
65
|
-
else
|
66
|
-
render('tail.erb', :locals => {
|
67
|
-
:id => id,
|
68
|
-
:path => File.basename(path),
|
69
|
-
:update => true,
|
70
|
-
:content => content
|
71
|
-
}, :layout => true)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def run
|
76
|
-
Thread.new { app.run }
|
77
|
-
redirect("/app/tail")
|
78
|
-
end
|
79
|
-
|
80
|
-
def stop
|
81
|
-
app.stop
|
82
|
-
redirect("/app/info")
|
83
|
-
end
|
84
|
-
|
85
|
-
def terminate
|
86
|
-
app.terminate
|
87
|
-
redirect("/app/info")
|
88
|
-
end
|
89
|
-
|
90
|
-
def help(key=nil)
|
91
|
-
end
|
92
|
-
end
|
@@ -1,255 +0,0 @@
|
|
1
|
-
require 'tap/controller'
|
2
|
-
|
3
|
-
class SchemaController < Tap::Controller
|
4
|
-
set :default_layout, 'layout.erb'
|
5
|
-
|
6
|
-
# Initializes a new schema and redirects to display.
|
7
|
-
def index
|
8
|
-
id = initialize_schema
|
9
|
-
redirect("/schema/display/#{id}")
|
10
|
-
end
|
11
|
-
|
12
|
-
# Loads the schema indicated by id and renders 'schema.erb' with the default
|
13
|
-
# layout.
|
14
|
-
def display(id)
|
15
|
-
schema = load_schema(id)
|
16
|
-
render 'schema.erb', :locals => {
|
17
|
-
:id => id,
|
18
|
-
:schema => schema
|
19
|
-
}, :layout => true
|
20
|
-
end
|
21
|
-
|
22
|
-
# Updates the specified schema with the request parameters. Update forwards
|
23
|
-
# the request to the action ('add' or 'remove') specified in the action
|
24
|
-
# parameter.
|
25
|
-
def update(id)
|
26
|
-
case request['action']
|
27
|
-
when 'add' then add(id)
|
28
|
-
when 'remove' then remove(id)
|
29
|
-
when 'echo' then echo
|
30
|
-
else raise Tap::ServerError, "unknown action: #{request['action']}"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# Adds nodes or joins to the schema. Parameters:
|
35
|
-
#
|
36
|
-
# nodes[]:: An array of nodes to add to the schema. Each entry is split using
|
37
|
-
# Shellwords to yield an argv; the argv initializes the node. The
|
38
|
-
# index of each new node is added to targets[].
|
39
|
-
# sources[]:: An array of source node indicies used to create a join.
|
40
|
-
# targets[]:: An array of target node indicies used to create a join (note
|
41
|
-
# the indicies of new nodes are added to targets).
|
42
|
-
#
|
43
|
-
# Add creates and pushes new nodes onto schema as specified in nodes, then
|
44
|
-
# creates joins between the sources and targets. The join class is inferred
|
45
|
-
# by Utils.infer_join; if no join can be inferred the join class is
|
46
|
-
# effectively nil, and consistent with that, the node output for sources
|
47
|
-
# and the node input for targets is set to nil.
|
48
|
-
#
|
49
|
-
# === Notes
|
50
|
-
#
|
51
|
-
# The nomenclature for source and target is relative to the join, and may
|
52
|
-
# seem backwards for the node (ex: 'sources[]=0&targets[]=1' makes a join
|
53
|
-
# like '0:1')
|
54
|
-
#
|
55
|
-
def add(id)
|
56
|
-
unless request.post?
|
57
|
-
raise Tap::ServerError, "add must be performed with post"
|
58
|
-
end
|
59
|
-
|
60
|
-
round = (request['round'] || 0).to_i
|
61
|
-
outputs = (request['outputs[]'] || []).collect {|index| index.to_i }
|
62
|
-
inputs = (request['inputs[]'] || []).collect {|index| index.to_i }
|
63
|
-
nodes = request['nodes[]'] || []
|
64
|
-
|
65
|
-
load_schema(id) do |schema|
|
66
|
-
nodes.each do |arg|
|
67
|
-
next unless arg && !arg.empty?
|
68
|
-
|
69
|
-
outputs << schema.nodes.length
|
70
|
-
schema.nodes << Tap::Support::Node.new(Shellwords.shellwords(arg), round)
|
71
|
-
end
|
72
|
-
|
73
|
-
if inputs.empty? || outputs.empty?
|
74
|
-
inputs.each {|index| schema[index].output = nil }
|
75
|
-
outputs.each {|index| schema[index].input = round }
|
76
|
-
else
|
77
|
-
|
78
|
-
# temporary
|
79
|
-
if inputs.length > 1 && outputs.length > 1
|
80
|
-
raise "multi-way join specified"
|
81
|
-
end
|
82
|
-
|
83
|
-
schema.set(Tap::Support::Join, inputs, outputs)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
redirect("/schema/display/#{id}")
|
88
|
-
end
|
89
|
-
|
90
|
-
# Removes nodes or joins from the schema. Parameters:
|
91
|
-
#
|
92
|
-
# sources[]:: An array of source node indicies to remove.
|
93
|
-
# targets[]:: An array of target node indicies to remove.
|
94
|
-
#
|
95
|
-
# Normally remove sets the node.output for each source to nil and the
|
96
|
-
# node.input for each target to nil. However, if a node is indicated in
|
97
|
-
# both sources and targets AND it has no join input/output, then it will
|
98
|
-
# be removed.
|
99
|
-
#
|
100
|
-
# === Notes
|
101
|
-
#
|
102
|
-
# The nomenclature for source and target is relative to the join, and may
|
103
|
-
# seem backwards for the node (ex: for the sequence '0:1:2', 'targets[]=1'
|
104
|
-
# breaks the join '0:1' while 'sources[]=1' breaks the join '1:2'.
|
105
|
-
#
|
106
|
-
def remove(id)
|
107
|
-
unless request.post?
|
108
|
-
raise Tap::ServerError, "remove must be performed with post"
|
109
|
-
end
|
110
|
-
|
111
|
-
round = (request['round'] || 0).to_i
|
112
|
-
outputs = (request['outputs[]'] || []).collect {|index| index.to_i }
|
113
|
-
inputs = (request['inputs[]'] || []).collect {|index| index.to_i }
|
114
|
-
|
115
|
-
load_schema(id) do |schema|
|
116
|
-
# Remove joins. Removed indicies are popped to ensure
|
117
|
-
# that if a join was removed the node will not be.
|
118
|
-
outputs.delete_if do |index|
|
119
|
-
next unless node = schema.nodes[index]
|
120
|
-
if node.input_join
|
121
|
-
node.input = round
|
122
|
-
true
|
123
|
-
else
|
124
|
-
false
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
inputs.delete_if do |index|
|
129
|
-
next unless node = schema.nodes[index]
|
130
|
-
if node.output_join
|
131
|
-
node.output = nil
|
132
|
-
true
|
133
|
-
else
|
134
|
-
false
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
# Remove nodes. Setting a node to nil causes it's removal during
|
139
|
-
# compact; orphaned joins are removed during compact as well.
|
140
|
-
(inputs & outputs).each do |index|
|
141
|
-
schema.nodes[index] = nil
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
redirect("/schema/display/#{id}")
|
146
|
-
end
|
147
|
-
|
148
|
-
def submit(id)
|
149
|
-
case request['action']
|
150
|
-
when 'save' then save(id)
|
151
|
-
when 'preview' then preview(id)
|
152
|
-
when 'echo' then echo
|
153
|
-
when 'run'
|
154
|
-
dump_schema(id, schema)
|
155
|
-
run(id)
|
156
|
-
else raise Tap::ServerError, "unknown action: #{request['action']}"
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
def save(id)
|
161
|
-
unless request.post?
|
162
|
-
raise Tap::ServerError, "submit must be performed with post"
|
163
|
-
end
|
164
|
-
|
165
|
-
dump_schema(id, schema)
|
166
|
-
redirect("/schema/display/#{id}")
|
167
|
-
end
|
168
|
-
|
169
|
-
def preview(id)
|
170
|
-
response.headers['Content-Type'] = 'text/plain'
|
171
|
-
render('preview.erb', :locals => {:id => id, :schema => schema})
|
172
|
-
end
|
173
|
-
|
174
|
-
def run(id)
|
175
|
-
unless request.post?
|
176
|
-
raise Tap::ServerError, "run must be performed with post"
|
177
|
-
end
|
178
|
-
|
179
|
-
# it would be nice to someday put all this on a separate thread...
|
180
|
-
schema = load_schema(id)
|
181
|
-
tasks = server.env.tasks
|
182
|
-
schema.build(app) do |(key, *args)|
|
183
|
-
if const = tasks.search(key)
|
184
|
-
const.constantize.parse(args, app) do |help|
|
185
|
-
raise "help not implemented"
|
186
|
-
#redirect("/app/help/#{key}")
|
187
|
-
end
|
188
|
-
else
|
189
|
-
raise ArgumentError, "unknown task: #{key}"
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
Thread.new { app.run }
|
194
|
-
redirect("/app/tail")
|
195
|
-
end
|
196
|
-
|
197
|
-
protected
|
198
|
-
|
199
|
-
# Parses a Tap::Support::Schema from the request.
|
200
|
-
def schema
|
201
|
-
argv = request['argv[]'] || []
|
202
|
-
argv.delete_if {|arg| arg.empty? }
|
203
|
-
Tap::Support::Schema.parse(argv)
|
204
|
-
end
|
205
|
-
|
206
|
-
def initialize_schema
|
207
|
-
current = root.glob(:schema, "*").collect {|path| File.basename(path).chomp(".yml") }
|
208
|
-
|
209
|
-
id = random_key(current.length)
|
210
|
-
while current.include?(id)
|
211
|
-
id = random_key(current.length)
|
212
|
-
end
|
213
|
-
|
214
|
-
dump_schema(id, schema)
|
215
|
-
id
|
216
|
-
end
|
217
|
-
|
218
|
-
def load_schema(id)
|
219
|
-
unless path = root.filepath(:schema, "#{id}.yml")
|
220
|
-
raise ServerError, "no schema for id: #{id}"
|
221
|
-
end
|
222
|
-
schema = Tap::Support::Schema.load_file(path)
|
223
|
-
|
224
|
-
if block_given?
|
225
|
-
result = yield(schema)
|
226
|
-
dump_schema(id, schema)
|
227
|
-
result
|
228
|
-
else
|
229
|
-
schema
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
def dump_schema(id, schema=nil)
|
234
|
-
root.prepare(:schema, "#{id}.yml") do |file|
|
235
|
-
file << YAML.dump(schema.dump) if schema
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
def instantiate(*argv)
|
240
|
-
key = argv.shift
|
241
|
-
tasc = server.env.tasks.search(key).constantize
|
242
|
-
tasc.parse(argv)
|
243
|
-
end
|
244
|
-
|
245
|
-
# helper to echo requests back... good for debugging
|
246
|
-
def echo # :nodoc:
|
247
|
-
"<pre>#{request.params.to_yaml}</pre>"
|
248
|
-
end
|
249
|
-
|
250
|
-
# Generates a random integer key.
|
251
|
-
def random_key(length) # :nodoc:
|
252
|
-
length = 1 if length < 1
|
253
|
-
rand(length * 10000).to_s
|
254
|
-
end
|
255
|
-
end
|