katte 0.0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +107 -0
- data/Rakefile +1 -0
- data/bin/katte +7 -0
- data/katte.gemspec +19 -0
- data/lib/katte.rb +50 -0
- data/lib/katte/command.rb +33 -0
- data/lib/katte/config.rb +21 -0
- data/lib/katte/driver.rb +71 -0
- data/lib/katte/environment.rb +14 -0
- data/lib/katte/filter.rb +22 -0
- data/lib/katte/node.rb +5 -0
- data/lib/katte/node/base.rb +48 -0
- data/lib/katte/node/collection.rb +47 -0
- data/lib/katte/plugins.rb +11 -0
- data/lib/katte/plugins/base.rb +38 -0
- data/lib/katte/plugins/file_type.rb +47 -0
- data/lib/katte/plugins/file_type/bash.rb +9 -0
- data/lib/katte/plugins/file_type/debug.rb +14 -0
- data/lib/katte/plugins/file_type/hive.rb +9 -0
- data/lib/katte/plugins/file_type/r.rb +9 -0
- data/lib/katte/plugins/file_type/ruby.rb +9 -0
- data/lib/katte/plugins/node.rb +6 -0
- data/lib/katte/plugins/node/debug.rb +11 -0
- data/lib/katte/plugins/node/file.rb +45 -0
- data/lib/katte/plugins/output.rb +13 -0
- data/lib/katte/plugins/output/debug.rb +14 -0
- data/lib/katte/plugins/output/file.rb +31 -0
- data/lib/katte/plugins/output/stderr.rb +9 -0
- data/lib/katte/plugins/output/stdoe.rb +14 -0
- data/lib/katte/recipe.rb +8 -0
- data/lib/katte/recipe/file_type.rb +29 -0
- data/lib/katte/recipe/node.rb +71 -0
- data/lib/katte/recipe/node_factory.rb +57 -0
- data/lib/katte/runner.rb +66 -0
- data/lib/katte/runner/callback.rb +36 -0
- data/lib/katte/thread_pool.rb +41 -0
- data/lib/katte/version.rb +3 -0
- data/spec/katte/config_spec.rb +16 -0
- data/spec/katte/driver_spec.rb +58 -0
- data/spec/katte/filter_spec.rb +19 -0
- data/spec/katte/node/base_spec.rb +20 -0
- data/spec/katte/node/collection_spec.rb +36 -0
- data/spec/katte/plugins/file_type_spec.rb +59 -0
- data/spec/katte/plugins/output_spec.rb +31 -0
- data/spec/katte/recipe/node_factory_spec.rb +20 -0
- data/spec/katte/runner_spec.rb +34 -0
- data/spec/katte/thread_pool_spec.rb +47 -0
- data/spec/recipes/custom/sample_1.sh +3 -0
- data/spec/recipes/custom/sample_2.sh +3 -0
- data/spec/recipes/test/sample.sh +5 -0
- data/spec/recipes/test/sample/sub.sh +3 -0
- data/spec/spec_helper.rb +7 -0
- metadata +117 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
class Katte::Node::Collection
|
2
|
+
include Enumerable
|
3
|
+
|
4
|
+
def each &proc
|
5
|
+
@nodes.values.each &proc
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@nodes = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def all
|
13
|
+
@nodes.values
|
14
|
+
end
|
15
|
+
def find(node_name)
|
16
|
+
@nodes[node_name]
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(node, params = {})
|
20
|
+
@nodes[node.name] = node
|
21
|
+
end
|
22
|
+
alias :<< :add
|
23
|
+
|
24
|
+
def connect
|
25
|
+
cache ||= {} # connection cache
|
26
|
+
|
27
|
+
@nodes.values.each do |node|
|
28
|
+
# connect self to parents if exist
|
29
|
+
node.requires.each do |req, prm|
|
30
|
+
if @nodes[req]
|
31
|
+
node.add_parent(@nodes[req], *prm)
|
32
|
+
@nodes[req].add_child(node, *prm)
|
33
|
+
else
|
34
|
+
(cache[req] ||= []) << [node, prm]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# connect children to self
|
39
|
+
if children = cache.delete(node.name)
|
40
|
+
children.each {|c, prm|
|
41
|
+
c.add_parent(node, *prm)
|
42
|
+
node.add_child(c, *prm)
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'katte/plugins/base'
|
2
|
+
require 'katte/plugins/file_type'
|
3
|
+
require 'katte/plugins/output'
|
4
|
+
require 'katte/plugins/node'
|
5
|
+
|
6
|
+
module Katte::Plugins
|
7
|
+
end
|
8
|
+
|
9
|
+
Dir[File.expand_path('../plugins/file_type/*.rb', __FILE__),
|
10
|
+
File.expand_path('../plugins/output/*.rb' , __FILE__),
|
11
|
+
File.expand_path('../plugins/node/*.rb' , __FILE__)].each {|p| require p }
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Katte::Plugins
|
2
|
+
module Base
|
3
|
+
def class_methods
|
4
|
+
@class_methods ||= Module.new
|
5
|
+
end
|
6
|
+
private :class_methods
|
7
|
+
|
8
|
+
def included(klass)
|
9
|
+
klass.extend class_methods
|
10
|
+
end
|
11
|
+
|
12
|
+
def index(keyword = nil)
|
13
|
+
return @index unless keyword
|
14
|
+
@index = keyword
|
15
|
+
end
|
16
|
+
def define_keyword(keyword)
|
17
|
+
klass = self
|
18
|
+
|
19
|
+
class_methods.send(:define_method, keyword) {|value|
|
20
|
+
define_method(keyword) { value }
|
21
|
+
|
22
|
+
if klass.index == keyword
|
23
|
+
klass.register(value, self.new)
|
24
|
+
end
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def plugins
|
29
|
+
@plugins ||= {}
|
30
|
+
end
|
31
|
+
def register(index, plugin)
|
32
|
+
plugins[index] = plugin
|
33
|
+
end
|
34
|
+
def find(index)
|
35
|
+
plugins[index]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Katte::Plugins::FileType
|
3
|
+
extend Katte::Plugins::Base
|
4
|
+
|
5
|
+
define_keyword :comment_by
|
6
|
+
define_keyword :extname
|
7
|
+
index :extname
|
8
|
+
|
9
|
+
def simple_exec(node, program, *args)
|
10
|
+
node.open {|out, err|
|
11
|
+
system(Katte.app.env.to_hash, program, *args, :out => out, :err => err)
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse(path)
|
16
|
+
c = Regexp.escape(comment_by)
|
17
|
+
@comment_pattern ||= /^#{c}|^\s*$/
|
18
|
+
@directive_pattern ||= %r{
|
19
|
+
^#{c}\s* # comment
|
20
|
+
(?<key>\w+)\s*:\s* # key
|
21
|
+
(?<value>[^(\s]+) # value
|
22
|
+
(\((?<params>[^)]*)\))? # param (optional)
|
23
|
+
$
|
24
|
+
}x
|
25
|
+
|
26
|
+
directive = Hash.new {|h,k| h[k] = [] }
|
27
|
+
open(path) do |io|
|
28
|
+
while line = io.gets
|
29
|
+
line.chomp!
|
30
|
+
break unless @comment_pattern.match(line)
|
31
|
+
next unless m = @directive_pattern.match(line)
|
32
|
+
|
33
|
+
key = m[:key]
|
34
|
+
value = m[:value].strip
|
35
|
+
params = m[:params] && m[:params].split(',').map(&:strip).map(&method(:convert_variable))
|
36
|
+
|
37
|
+
directive[key] << [value, params]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
directive
|
41
|
+
end
|
42
|
+
|
43
|
+
def convert_variable(value)
|
44
|
+
# #{xx} というパターンを env['xx'] で置換する
|
45
|
+
value.gsub(/\#\{((?:\\\{|[^\{])+)\}/) {|m| Katte.app.env.to_hash[$1]}
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Katte::Plugins::FileType::Debug
|
2
|
+
include Katte::Plugins::FileType
|
3
|
+
|
4
|
+
extname :debug
|
5
|
+
|
6
|
+
class Abort < StandardError; end
|
7
|
+
|
8
|
+
def execute(node)
|
9
|
+
node.options['callback'].each {|cb| cb.call(node) }
|
10
|
+
return true
|
11
|
+
rescue Abort => e
|
12
|
+
return false
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Katte::Plugins::Node::File
|
2
|
+
include Katte::Node::Base
|
3
|
+
include Katte::Plugins::Node
|
4
|
+
|
5
|
+
name 'file'
|
6
|
+
|
7
|
+
def duration; 30; end
|
8
|
+
|
9
|
+
def add_child(node, *params)
|
10
|
+
file = params.first
|
11
|
+
return unless file
|
12
|
+
add_watch_list(file, node)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run(driver)
|
16
|
+
until watching_files.empty?
|
17
|
+
update_watch_list do |file, nodes|
|
18
|
+
if FileTest.exist? file
|
19
|
+
nodes.each {|n| driver.next(self, n.name) }
|
20
|
+
true
|
21
|
+
else
|
22
|
+
false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
watching_files.each {|f| Katte.app.logger.info("wating: #{f}") }
|
27
|
+
sleep duration * 60 unless watching_files.empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
driver.done(self)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def watching_files
|
35
|
+
(@watch_list || {}).keys
|
36
|
+
end
|
37
|
+
def add_watch_list(file, node)
|
38
|
+
@watch_list ||= {}
|
39
|
+
(@watch_list[file] ||= []) << node
|
40
|
+
end
|
41
|
+
def update_watch_list(&proc)
|
42
|
+
@watch_list ||= {}
|
43
|
+
@watch_list = @watch_list.reject(&proc)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
class Katte::Plugins::Output::File_
|
4
|
+
include Katte::Plugins::Output
|
5
|
+
name :file
|
6
|
+
|
7
|
+
def out(node, data)
|
8
|
+
return data if data.empty?
|
9
|
+
|
10
|
+
file = File.join(Katte.app.config.result_root,
|
11
|
+
node.name + '.out',
|
12
|
+
Katte.app.env.to_hash['date'] + ".txt")
|
13
|
+
|
14
|
+
FileUtils.makedirs(File.dirname(file))
|
15
|
+
|
16
|
+
File.open(file, 'w') {|f| f.print data }
|
17
|
+
end
|
18
|
+
|
19
|
+
def err(node, data)
|
20
|
+
return data if data.empty?
|
21
|
+
|
22
|
+
file = File.join(Katte.app.config.log_root,
|
23
|
+
'recipes',
|
24
|
+
node.name + '.log',
|
25
|
+
Katte.app.env.to_hash['date'] + ".txt")
|
26
|
+
|
27
|
+
FileUtils.makedirs(File.dirname(file))
|
28
|
+
|
29
|
+
File.open(file, 'a') {|f| f.print data }
|
30
|
+
end
|
31
|
+
end
|
data/lib/katte/recipe.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Katte::Recipe::FileType
|
2
|
+
class <<self
|
3
|
+
def table
|
4
|
+
@table ||= {}
|
5
|
+
end
|
6
|
+
private :table
|
7
|
+
|
8
|
+
def register(file_type, extname = nil)
|
9
|
+
extname ||= file_type.extname
|
10
|
+
table[extname] = file_type
|
11
|
+
end
|
12
|
+
|
13
|
+
def find(extname)
|
14
|
+
table[extname] || Katte::Plugins::FileType.find(extname)
|
15
|
+
end
|
16
|
+
def register_builtin_file_types
|
17
|
+
Dir[File.expand_path('../plugins/file_type/*.rb', __FILE__)].each {|p|
|
18
|
+
require p
|
19
|
+
name = File.basename(p, ".rb")
|
20
|
+
klass = "katte/plugins/file_type/#{name}".camelize.constantize
|
21
|
+
}
|
22
|
+
register(Katte::Plugins::FileType::Bash.new)
|
23
|
+
register(Katte::Plugins::FileType::Debug.new)
|
24
|
+
register(Katte::Plugins::FileType::Hive.new)
|
25
|
+
register(Katte::Plugins::FileType::R.new)
|
26
|
+
register(Katte::Plugins::FileType::Ruby.new)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'katte/node/base'
|
2
|
+
require 'katte/recipe/node_factory'
|
3
|
+
require 'katte/thread_pool'
|
4
|
+
|
5
|
+
module Katte::Recipe
|
6
|
+
class Node
|
7
|
+
include Katte::Node::Base
|
8
|
+
|
9
|
+
%w(name path file_type output period options).each {|attr|
|
10
|
+
attr_accessor attr
|
11
|
+
}
|
12
|
+
|
13
|
+
def initialize(params)
|
14
|
+
@name = params[:name]
|
15
|
+
@path = params[:path]
|
16
|
+
@requires = params[:require]
|
17
|
+
@file_type = params[:file_type]
|
18
|
+
@output = params[:output] || []
|
19
|
+
@period = params[:period] || 'day'
|
20
|
+
@options = params[:options] || {}
|
21
|
+
|
22
|
+
@parents = []
|
23
|
+
@children = []
|
24
|
+
end
|
25
|
+
|
26
|
+
def open
|
27
|
+
out_r, out_w = IO.pipe
|
28
|
+
err_r, err_w = IO.pipe
|
29
|
+
|
30
|
+
result = yield out_w, err_w
|
31
|
+
|
32
|
+
[out_w, err_w].each {|io| io.close unless io.closed? }
|
33
|
+
out_a, err_a = out_r.to_a.join, err_r.to_a.join
|
34
|
+
[out_r, err_r].each {|io| io.close unless io.closed? }
|
35
|
+
|
36
|
+
Katte.app.logger.warn("#{self.name} -- result is empty") if out_a.empty?
|
37
|
+
|
38
|
+
@output.reduce(out_a) {|stream, o| o.out(self, stream) }
|
39
|
+
@output.reduce(err_a) {|stream, o| o.err(self, stream) }
|
40
|
+
|
41
|
+
result
|
42
|
+
ensure
|
43
|
+
[out_r, out_w, err_r, err_w].each {|io| io.close unless io.closed? }
|
44
|
+
end
|
45
|
+
|
46
|
+
def run(driver)
|
47
|
+
unless @file_type
|
48
|
+
Katte.app.logger.error("no file type specified for %s" % @name)
|
49
|
+
return
|
50
|
+
end
|
51
|
+
|
52
|
+
Katte::ThreadPool.instance.push {
|
53
|
+
Katte.app.logger.info("[start] #{self.name}")
|
54
|
+
result = file_type.execute(self)
|
55
|
+
Katte.app.logger.info(sprintf("[%s] #{self.name}", (result ? "success" : "fail")))
|
56
|
+
|
57
|
+
result ? driver.done(self) : driver.fail(self)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
def descendants
|
61
|
+
Enumerator.new {|enum| _descendants(enum) }
|
62
|
+
end
|
63
|
+
def _descendants(enum)
|
64
|
+
children.each {|node|
|
65
|
+
enum << node
|
66
|
+
node._descendants(enum)
|
67
|
+
}
|
68
|
+
enum
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|