katte 0.0.1.3
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/.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
|