katte 0.0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/.gitignore +17 -0
  2. data/.ruby-version +1 -0
  3. data/Gemfile +9 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +107 -0
  6. data/Rakefile +1 -0
  7. data/bin/katte +7 -0
  8. data/katte.gemspec +19 -0
  9. data/lib/katte.rb +50 -0
  10. data/lib/katte/command.rb +33 -0
  11. data/lib/katte/config.rb +21 -0
  12. data/lib/katte/driver.rb +71 -0
  13. data/lib/katte/environment.rb +14 -0
  14. data/lib/katte/filter.rb +22 -0
  15. data/lib/katte/node.rb +5 -0
  16. data/lib/katte/node/base.rb +48 -0
  17. data/lib/katte/node/collection.rb +47 -0
  18. data/lib/katte/plugins.rb +11 -0
  19. data/lib/katte/plugins/base.rb +38 -0
  20. data/lib/katte/plugins/file_type.rb +47 -0
  21. data/lib/katte/plugins/file_type/bash.rb +9 -0
  22. data/lib/katte/plugins/file_type/debug.rb +14 -0
  23. data/lib/katte/plugins/file_type/hive.rb +9 -0
  24. data/lib/katte/plugins/file_type/r.rb +9 -0
  25. data/lib/katte/plugins/file_type/ruby.rb +9 -0
  26. data/lib/katte/plugins/node.rb +6 -0
  27. data/lib/katte/plugins/node/debug.rb +11 -0
  28. data/lib/katte/plugins/node/file.rb +45 -0
  29. data/lib/katte/plugins/output.rb +13 -0
  30. data/lib/katte/plugins/output/debug.rb +14 -0
  31. data/lib/katte/plugins/output/file.rb +31 -0
  32. data/lib/katte/plugins/output/stderr.rb +9 -0
  33. data/lib/katte/plugins/output/stdoe.rb +14 -0
  34. data/lib/katte/recipe.rb +8 -0
  35. data/lib/katte/recipe/file_type.rb +29 -0
  36. data/lib/katte/recipe/node.rb +71 -0
  37. data/lib/katte/recipe/node_factory.rb +57 -0
  38. data/lib/katte/runner.rb +66 -0
  39. data/lib/katte/runner/callback.rb +36 -0
  40. data/lib/katte/thread_pool.rb +41 -0
  41. data/lib/katte/version.rb +3 -0
  42. data/spec/katte/config_spec.rb +16 -0
  43. data/spec/katte/driver_spec.rb +58 -0
  44. data/spec/katte/filter_spec.rb +19 -0
  45. data/spec/katte/node/base_spec.rb +20 -0
  46. data/spec/katte/node/collection_spec.rb +36 -0
  47. data/spec/katte/plugins/file_type_spec.rb +59 -0
  48. data/spec/katte/plugins/output_spec.rb +31 -0
  49. data/spec/katte/recipe/node_factory_spec.rb +20 -0
  50. data/spec/katte/runner_spec.rb +34 -0
  51. data/spec/katte/thread_pool_spec.rb +47 -0
  52. data/spec/recipes/custom/sample_1.sh +3 -0
  53. data/spec/recipes/custom/sample_2.sh +3 -0
  54. data/spec/recipes/test/sample.sh +5 -0
  55. data/spec/recipes/test/sample/sub.sh +3 -0
  56. data/spec/spec_helper.rb +7 -0
  57. 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,9 @@
1
+ class Katte::Plugins::FileType::Bash
2
+ include Katte::Plugins::FileType
3
+ extname 'sh'
4
+ comment_by '#'
5
+
6
+ def execute(node)
7
+ simple_exec(node, 'bash', node.path)
8
+ end
9
+ 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,9 @@
1
+ class Katte::Plugins::FileType::Hive
2
+ include Katte::Plugins::FileType
3
+ extname 'sql'
4
+ comment_by '--'
5
+
6
+ def execute(node)
7
+ simple_exec(node, 'hive', '-f', node.path)
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Katte::Plugins::FileType::R
2
+ include Katte::Plugins::FileType
3
+ extname 'R'
4
+ comment_by '#'
5
+
6
+ def execute(node)
7
+ simple_exec(node, 'Rscript', node.path)
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Katte::Plugins::FileType::Rubyn
2
+ include Katte::Plugins::FileType
3
+ extname 'rb'
4
+ comment_by '#'
5
+
6
+ def execute(node)
7
+ simple_exec(node, 'ruby', node.path)
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Katte::Plugins::Node
2
+ extend Katte::Plugins::Base
3
+
4
+ define_keyword :name
5
+ index :name
6
+ end
@@ -0,0 +1,11 @@
1
+ class Katte::Plugins::Node::Debug
2
+ include Katte::Node::Base
3
+ include Katte::Plugins::Node
4
+
5
+ name 'debug'
6
+
7
+ def run(driver)
8
+ children.each {|child| driver.next(self, child.name) }
9
+ driver.done(self)
10
+ end
11
+ 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,13 @@
1
+ module Katte::Plugins::Output
2
+ extend Katte::Plugins::Base
3
+
4
+ define_keyword :name
5
+ index :name
6
+
7
+ def out(node, output)
8
+ output
9
+ end
10
+ def err(node, output)
11
+ output
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ class Katte::Plugins::Output::Debug
2
+ include Katte::Plugins::Output
3
+ name :debug
4
+
5
+ def history
6
+ @history ||= Queue.new
7
+ end
8
+
9
+ def out(node, data)
10
+ history.push(node: node, out: data)
11
+
12
+ data
13
+ end
14
+ 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
@@ -0,0 +1,9 @@
1
+ class Katte::Plugins::Output::Stderr
2
+ include Katte::Plugins::Output
3
+ name :stderr
4
+
5
+ def err(node, data)
6
+ STDERR.puts data
7
+ data
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ class Katte::Plugins::Output::Stdoe
2
+ include Katte::Plugins::Output
3
+ name :stdoe
4
+
5
+ def out(node, data)
6
+ STDIN.puts data
7
+ data
8
+ end
9
+
10
+ def err(node, data)
11
+ STDERR.puts data
12
+ data
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ class Katte
2
+ module Recipe
3
+ end
4
+ end
5
+
6
+ require 'katte/recipe/file_type'
7
+ require 'katte/recipe/node'
8
+ require 'katte/recipe/node_factory'
@@ -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