triglav-agent 1.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +6 -0
  5. data/.yardopts +6 -0
  6. data/CHANGELOG.md +3 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +5 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +59 -0
  11. data/Rakefile +11 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/docs/Triglav/Agent/ApiClient/AuthenticationError.html +150 -0
  15. data/docs/Triglav/Agent/ApiClient/ConnectionError.html +150 -0
  16. data/docs/Triglav/Agent/ApiClient/Error.html +296 -0
  17. data/docs/Triglav/Agent/ApiClient.html +545 -0
  18. data/docs/Triglav/Agent/Base/CLI.html +498 -0
  19. data/docs/Triglav/Agent/Base/Connection.html +258 -0
  20. data/docs/Triglav/Agent/Base/Monitor.html +370 -0
  21. data/docs/Triglav/Agent/Base/Processor.html +623 -0
  22. data/docs/Triglav/Agent/Base/Setting.html +1081 -0
  23. data/docs/Triglav/Agent/Base/Worker.html +635 -0
  24. data/docs/Triglav/Agent/Base.html +121 -0
  25. data/docs/Triglav/Agent/Configuration.html +967 -0
  26. data/docs/Triglav/Agent/Error.html +130 -0
  27. data/docs/Triglav/Agent/HashUtil.html +351 -0
  28. data/docs/Triglav/Agent/LogFormatter.html +271 -0
  29. data/docs/Triglav/Agent/Logger.html +287 -0
  30. data/docs/Triglav/Agent/StorageFile.html +1130 -0
  31. data/docs/Triglav/Agent/Timer.html +424 -0
  32. data/docs/Triglav/Agent/TooManyError.html +134 -0
  33. data/docs/Triglav/Agent.html +131 -0
  34. data/docs/Triglav.html +119 -0
  35. data/docs/_index.html +335 -0
  36. data/docs/class_list.html +51 -0
  37. data/docs/css/common.css +1 -0
  38. data/docs/css/full_list.css +58 -0
  39. data/docs/css/style.css +481 -0
  40. data/docs/file.LICENSE.html +72 -0
  41. data/docs/file.README.html +137 -0
  42. data/docs/file_list.html +61 -0
  43. data/docs/frames.html +17 -0
  44. data/docs/index.html +137 -0
  45. data/docs/js/app.js +243 -0
  46. data/docs/js/full_list.js +216 -0
  47. data/docs/js/jquery.js +4 -0
  48. data/docs/method_list.html +659 -0
  49. data/docs/top-level-namespace.html +112 -0
  50. data/example/config.yml +40 -0
  51. data/lib/triglav/agent/api_client.rb +199 -0
  52. data/lib/triglav/agent/base/cli.rb +98 -0
  53. data/lib/triglav/agent/base/connection.rb +30 -0
  54. data/lib/triglav/agent/base/monitor.rb +32 -0
  55. data/lib/triglav/agent/base/processor.rb +136 -0
  56. data/lib/triglav/agent/base/setting.rb +112 -0
  57. data/lib/triglav/agent/base/worker.rb +95 -0
  58. data/lib/triglav/agent/configuration.rb +79 -0
  59. data/lib/triglav/agent/error.rb +4 -0
  60. data/lib/triglav/agent/hash_util.rb +36 -0
  61. data/lib/triglav/agent/logger.rb +50 -0
  62. data/lib/triglav/agent/storage_file.rb +144 -0
  63. data/lib/triglav/agent/timer.rb +80 -0
  64. data/lib/triglav/agent/version.rb +5 -0
  65. data/lib/triglav/agent.rb +20 -0
  66. data/lib/triglav-agent.rb +1 -0
  67. data/triglav-agent.gemspec +33 -0
  68. metadata +250 -0
@@ -0,0 +1,112 @@
1
+ require 'triglav/agent/hash_util'
2
+ require 'triglav/agent/logger'
3
+ require 'yaml'
4
+ require 'erb'
5
+
6
+ module Triglav::Agent
7
+ module Base
8
+ # A base class represents settings coming from config.yml and cli options
9
+ #
10
+ # This base class usually should be enough for agent plugins, but
11
+ # you can override this class and configure with Configuration#setting_class=
12
+ class Setting
13
+ attr_reader :cli_options
14
+
15
+ DEFAULT_LOG = 'STDOUT'.freeze
16
+ DEFAULT_LOG_LEVEL = 'info'.freeze
17
+ DEFAULT_APP_ENV = 'development'.freeze
18
+
19
+ def initialize(cli_options = {})
20
+ @cli_options = cli_options
21
+ if dotenv?
22
+ require 'dotenv'
23
+ Dotenv.load
24
+ end
25
+ end
26
+
27
+ def reload
28
+ Dotenv.overload if dotenv?
29
+ @config = nil
30
+ @logger.close rescue nil
31
+ @logger = nil
32
+ end
33
+
34
+ def app_env
35
+ @app_env ||= ENV['APP_ENV'] || DEFAULT_APP_ENV
36
+ end
37
+
38
+ def config_file
39
+ @cli_options[:config]
40
+ end
41
+
42
+ def status_file
43
+ @status_file ||= @cli_options[:status] || config.dig(:triglav, :status_file) || 'status.yml'
44
+ end
45
+
46
+ def token_file
47
+ @token_file ||= @cli_options[:token] || config.dig(:triglav, :token_file) || 'token.yml'
48
+ end
49
+
50
+ def dotenv?
51
+ @cli_options[:dotenv]
52
+ end
53
+
54
+ def debug?
55
+ @cli_options[:debug]
56
+ end
57
+
58
+ def logger
59
+ @logger ||= Logger.new(log, serverengine_logger_options)
60
+ end
61
+
62
+ def log_level
63
+ @cli_options[:log_level] || config.dig(:serverengine, :log_level) || DEFAULT_LOG_LEVEL
64
+ end
65
+
66
+ def log
67
+ @cli_options[:log] || config.dig(:serverengine, :log) || DEFAULT_LOG
68
+ end
69
+
70
+ def serverengine_options
71
+ serverengine_options = config[:serverengine].dup || {}
72
+ # serverengine_options[:workers] = 1 # default
73
+ # serverengine_options[:worker_type] = 'embedded' # default
74
+ serverengine_options.keys.each do |k|
75
+ serverengine_options.delete(k) if k.to_s.start_with?('log')
76
+ end
77
+ serverengine_options.merge!({
78
+ logger: logger,
79
+ log_level: log_level,
80
+ setting: self,
81
+ })
82
+ end
83
+
84
+ def [](key)
85
+ config[key]
86
+ end
87
+
88
+ def dig(*args)
89
+ config.dig(*args)
90
+ end
91
+
92
+ private
93
+
94
+ def config
95
+ @config ||=
96
+ begin
97
+ raw = File.read(config_file)
98
+ erb = ERB.new(raw, nil, "-").tap {|_| _.filename = config_file }
99
+ all = HashUtil.deep_symbolize_keys(YAML.load(erb.result(binding)))
100
+ all[app_env.to_sym]
101
+ end
102
+ end
103
+
104
+ def serverengine_logger_options
105
+ {
106
+ log: log,
107
+ log_level: log_level,
108
+ }
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,95 @@
1
+ require 'triglav/agent/timer'
2
+
3
+ module Triglav::Agent
4
+ module Base
5
+ # Triglav agent worker module for Serverengine.
6
+ #
7
+ # You usually do not need to customize this module, but if you want to
8
+ # implement your original, configure
9
+ #
10
+ # Triglav::Agent::Configuration.worker_module
11
+ module Worker
12
+ # serverengine interface
13
+ def initialize
14
+ @timer = Timer.new
15
+ end
16
+
17
+ # serverengine interface
18
+ def reload
19
+ $logger.info { "Worker#reload worker_id:#{worker_id}" }
20
+ $setting.reload
21
+ end
22
+
23
+ # serverengine interface
24
+ def run
25
+ $logger.info { "Worker#run worker_id:#{worker_id}" }
26
+ start
27
+ until @stop
28
+ @timer.wait(monitor_interval) { process }
29
+ end
30
+ rescue => e
31
+ # ServerEngine.dump_uncaught_error does not tell me e.class
32
+ log_error(e)
33
+ raise e
34
+ end
35
+
36
+ def process
37
+ started = Time.now
38
+ $logger.info { "Start Worker#process worker_id:#{worker_id}" }
39
+
40
+ total_count = 0
41
+ total_success_count = 0
42
+ resource_uri_prefixes.each do |resource_uri_prefix|
43
+ break if stopped?
44
+ processor = processor_class.new(self, resource_uri_prefix)
45
+ total_count += processor.total_count
46
+ total_success_count += processor.process
47
+ end
48
+
49
+ elapsed = Time.now - started
50
+ $logger.info {
51
+ "Finish Worker#process worker_id:#{worker_id} " \
52
+ "success_count/total_count:#{total_success_count}/#{total_count} elapsed:#{elapsed.to_f}sec"
53
+ }
54
+ end
55
+
56
+ def start
57
+ @timer.start
58
+ @stop = false
59
+ end
60
+
61
+ # serverengine interface
62
+ def stop
63
+ $logger.info { "Worker#stop worker_id:#{worker_id}" }
64
+ @stop = true
65
+ @timer.stop
66
+ end
67
+
68
+ def stopped?
69
+ @stop
70
+ end
71
+
72
+ private
73
+
74
+ def processor_class
75
+ Configuration.processor_class
76
+ end
77
+
78
+ def name
79
+ Configuration.name
80
+ end
81
+
82
+ def log_error(e)
83
+ $logger.error { "#{e.class} #{e.message} #{e.backtrace.join("\\n")}" } # one line
84
+ end
85
+
86
+ def monitor_interval
87
+ $setting.dig(name, :monitor_interval) || 60
88
+ end
89
+
90
+ def resource_uri_prefixes
91
+ $setting.dig(name, :connection_info).keys
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,79 @@
1
+ module Triglav
2
+ module Agent
3
+ # Configure Triglav::Agent framework
4
+ #
5
+ # require 'triglav/agent/configuration'
6
+ # require 'triglav/agent/vertica/worker'
7
+ # Triglav::Agent::Configuration.configure do |config|
8
+ # config.name = :vertica # default: :agent
9
+ # config.cli_class = Triglav::Agent::Vertica::CLI
10
+ # config.setting_class = Triglav::Agent::Vertica::Setting
11
+ # config.worker_module = Triglav::Agent::Vertica::Worker
12
+ # config.processor_class = Triglav::Agent::Vertica::Processor
13
+ # config.monitor_class = Triglav::Agent::Vertica::Monitor
14
+ # config.connection_class = Triglav::Agent::Vertica::Connection
15
+ # end
16
+ # Triglav::Agent::Configuration.cli_class.new.run
17
+ class Configuration
18
+ def self.configure(&block)
19
+ yield(Triglav::Agent::Configuration)
20
+ end
21
+
22
+ def self.worker_module
23
+ @worker_module ||= Triglav::Agent::Base::Worker
24
+ end
25
+
26
+ def self.processor_class
27
+ @processor_class ||= Triglav::Agent::Base::Processor
28
+ end
29
+
30
+ def self.monitor_class
31
+ @monitor_class ||= Triglav::Agent::Base::Monitor
32
+ end
33
+
34
+ def self.connection_class
35
+ @connection_class ||= Triglav::Agent::Base::Connection
36
+ end
37
+
38
+ def self.setting_class
39
+ @setting_class ||= Triglav::Agent::Base::Setting
40
+ end
41
+
42
+ def self.cli_class
43
+ @cli_class ||= Triglav::Agent::Base::CLI
44
+ end
45
+
46
+ def self.name
47
+ @name ||= :agent
48
+ end
49
+
50
+ def self.worker_module=(worker_module)
51
+ @worker_module = worker_module
52
+ end
53
+
54
+ def self.processor_class=(processor_class)
55
+ @processor_class = processor_class
56
+ end
57
+
58
+ def self.monitor_class=(monitor_class)
59
+ @monitor_class = monitor_class
60
+ end
61
+
62
+ def self.connection_class=(connection_class)
63
+ @connection_class = connection_class
64
+ end
65
+
66
+ def self.setting_class=(setting_class)
67
+ @setting_class = setting_class
68
+ end
69
+
70
+ def self.cli_class=(cli_class)
71
+ @cli_class = cli_class
72
+ end
73
+
74
+ def self.name=(name)
75
+ @name = name
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,4 @@
1
+ module Triglav::Agent
2
+ class Error < ::StandardError; end
3
+ class TooManyError < Error; end
4
+ end
@@ -0,0 +1,36 @@
1
+ module Triglav::Agent
2
+ class HashUtil
3
+ def self.deep_symbolize_keys(obj)
4
+ case obj
5
+ when Hash
6
+ obj.map {|k, v| [k.to_sym, deep_symbolize_keys(v)] }.to_h
7
+ when Array
8
+ obj.map {|v| deep_symbolize_keys(v) }
9
+ else
10
+ obj
11
+ end
12
+ end
13
+
14
+ def self.deep_stringify_keys(obj)
15
+ case obj
16
+ when Hash
17
+ obj.map {|k, v| [k.to_s, deep_stringify_keys(v)] }.to_h
18
+ when Array
19
+ obj.map {|v| deep_stringify_keys(v) }
20
+ else
21
+ obj
22
+ end
23
+ end
24
+
25
+ # HashUtil.setdig(hash, ['a', 'b'], 'bar') # like hash['a']['b'] = 'bar'
26
+ def self.setdig(hash, key, val)
27
+ keys = Array(key)
28
+ sub_hash = hash
29
+ keys[0...-1].each do |k|
30
+ sub_hash = (sub_hash[k] ||= {})
31
+ end
32
+ sub_hash[keys.last] = val
33
+ hash
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,50 @@
1
+ require 'serverengine/daemon_logger'
2
+
3
+ module Triglav::Agent
4
+ # Logger class
5
+ #
6
+ # require 'triglav/agent/logger'
7
+ # logger = Logger.new('STDOUT', opts = {})
8
+ class Logger < ::ServerEngine::DaemonLogger
9
+ def initialize(logdev, *args)
10
+ logdev = STDOUT if logdev == 'STDOUT'
11
+ logdev = STDERR if logdev == 'STDERR'
12
+ super(logdev, *args)
13
+ @formatter = LogFormatter.new
14
+ end
15
+
16
+ def write(msg)
17
+ @logdev.write msg
18
+ end
19
+ end
20
+
21
+ class LogFormatter
22
+ FORMAT = "%s [%s] %s %s\n"
23
+
24
+ def initialize(opts={})
25
+ end
26
+
27
+ def call(severity, time, progname, msg)
28
+ FORMAT % [format_datetime(time), severity, format_pid, format_message(msg)]
29
+ end
30
+
31
+ private
32
+ def format_datetime(time)
33
+ time.strftime("%Y-%m-%dT%H:%M:%S.%6N%:z")
34
+ end
35
+
36
+ def format_pid
37
+ "PID-#{::Process.pid} TID-#{Thread.current.object_id}"
38
+ end
39
+
40
+ def format_message(message)
41
+ case message
42
+ when ::Exception
43
+ e = message
44
+ "#{e.class} (#{e.message})\\n #{e.backtrace.join("\\n ")}"
45
+ else
46
+ message.to_s.gsub(/\n/, "\\n")
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,144 @@
1
+ require 'triglav/agent/hash_util'
2
+ require 'yaml'
3
+
4
+ module Triglav::Agent
5
+ # Thread and inter-process safe YAML file storage
6
+ #
7
+ # StorageFile.open($setting.status_file) do |fp|
8
+ # status = fp.load
9
+ # status['foo'] = 'bar'
10
+ # fp.dump(status)
11
+ # end
12
+ class StorageFile
13
+ attr_reader :fp
14
+
15
+ private def initialize(fp)
16
+ @fp = fp
17
+ end
18
+
19
+ # Load storage file
20
+ #
21
+ # StorageFile.load($setting.status_file)
22
+ #
23
+ # @param [String] path
24
+ # @return [Hash]
25
+ def self.load(path)
26
+ open(path) {|fp| fp.load }
27
+ end
28
+
29
+ # Open storage file
30
+ #
31
+ # StorageFile.open($setting.status_file) do |fp|
32
+ # status = fp.load
33
+ # status['foo'] = 'bar'
34
+ # fp.dump(status)
35
+ # end
36
+ #
37
+ # @param [String] path
38
+ # @param [Block] block
39
+ def self.open(path, &block)
40
+ fp = File.open(path, (File::RDONLY | File::CREAT))
41
+ until fp.flock(File::LOCK_EX | File::LOCK_NB)
42
+ $logger.info { "Somebody else is locking the storage file #{path.inspect}" }
43
+ sleep 0.5
44
+ end
45
+ begin
46
+ return yield(StorageFile.new(fp))
47
+ ensure
48
+ fp.flock(File::LOCK_UN)
49
+ fp.close rescue nil
50
+ end
51
+ end
52
+
53
+ # Set storage file with given key, value
54
+ #
55
+ # StorageFile.set($setting.status_file, 'foo', 'bar') # like h['foo'] = 'bar'
56
+ # StorageFile.set($setting.status_file, ['a','b'], 'bar') # like h['a']['b'] = 'bar'
57
+ #
58
+ # @param [String] path
59
+ # @param [Object] key
60
+ # @param [Object] val
61
+ def self.set(path, key, val)
62
+ keys = Array(key)
63
+ open(path) do |fp|
64
+ params = fp.load
65
+ HashUtil.setdig(params, keys, val)
66
+ fp.dump(params)
67
+ end
68
+ end
69
+
70
+ # Set key to hold val if key does not exist
71
+ #
72
+ # StorageFile.setnx($setting.status_file, 'foo', 'bar') # like h['foo'] = 'bar'
73
+ # StorageFile.setnx($setting.status_file, ['a','b'], 'bar') # like h['a']['b'] = 'bar'
74
+ #
75
+ # @param [String] path
76
+ # @param [Object] key
77
+ # @param [Object] val
78
+ # @return [Boolean] true if set (not exist), false if not set (exists)
79
+ def self.setnx(path, key, val)
80
+ keys = Array(key)
81
+ open(path) do |fp|
82
+ params = fp.load
83
+ return false if params.dig(*keys)
84
+ HashUtil.setdig(params, keys, val)
85
+ fp.dump(params)
86
+ return true
87
+ end
88
+ end
89
+
90
+ # Set key to hold val if key does not exist and returns the holded value
91
+ #
92
+ # This is a kind of atomic short hand of
93
+ #
94
+ # StorageFile.setnx($setting.status_file, 'foo', 'bar')
95
+ # StorageFile.get($setting.status_file, 'foo')
96
+ #
97
+ # @param [String] path
98
+ # @param [Object] key
99
+ # @param [Object] val
100
+ # @return [Object] holded value
101
+ def self.getsetnx(path, key, val)
102
+ keys = Array(key)
103
+ open(path) do |fp|
104
+ params = fp.load
105
+ if curr = params.dig(*keys)
106
+ return curr
107
+ end
108
+ HashUtil.setdig(params, keys, val)
109
+ fp.dump(params)
110
+ return val
111
+ end
112
+ end
113
+
114
+ # Get value of the given key from storage file
115
+ #
116
+ # StorageFile.get($setting.status_file, 'foo') # like h['foo'] = 'bar'
117
+ # StorageFile.get($setting.status_file, ['a','b']) # like hash['a']['b']
118
+ #
119
+ # @param [String] path
120
+ # @param [Object] key
121
+ def self.get(path, key)
122
+ keys = Array(key)
123
+ open(path) {|fp| fp.load.dig(*keys) }
124
+ end
125
+
126
+ # Load storage file
127
+ #
128
+ # @return [Hash]
129
+ def load
130
+ if !(content = @fp.read).empty?
131
+ YAML.load(content) # all keys must be symbols
132
+ else
133
+ {}
134
+ end
135
+ end
136
+
137
+ # Dump to storage file
138
+ #
139
+ # @param [Hash] hash
140
+ def dump(hash)
141
+ File.write(@fp.path, YAML.dump(hash))
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,80 @@
1
+ module Triglav::Agent
2
+ # A timer utility to run serverengine worker in a time interval
3
+ #
4
+ # module Triglav::Agent
5
+ # module Worker
6
+ # def initialize
7
+ # @interval = 60.0 # sec
8
+ # end
9
+ #
10
+ # def run
11
+ # @timer = Timer.new
12
+ # @stop = false
13
+ # until @stop
14
+ # @timer.wait(@interval) { process }
15
+ # end
16
+ # end
17
+ #
18
+ # def stop
19
+ # @stop = true
20
+ # @timer.stop
21
+ # end
22
+ # end
23
+ # end
24
+ class Timer
25
+ def initialize
26
+ @r, @w = IO.pipe
27
+ start
28
+ end
29
+
30
+ def wait(sec, &block)
31
+ return if @stop
32
+ started = Time.now
33
+ yield
34
+ elapsed = Time.now - started
35
+ if (timeout = (sec - elapsed).to_f) > 0
36
+ begin
37
+ IO.select([@r], [], [], timeout)
38
+ rescue IOError, Errno::EBADF
39
+ # these error may occur if @r is closed during IO.select. Ignore it
40
+ end
41
+ end
42
+ end
43
+
44
+ def start
45
+ @stop = false
46
+ end
47
+
48
+ def stop
49
+ @stop = true
50
+ signal
51
+ end
52
+
53
+ private
54
+
55
+ def signal
56
+ @w.puts ' '
57
+ end
58
+
59
+ # # Hmm, Ctrl-C breaks condvar.wait before calling #stop unexpectedly
60
+ # attr_reader :condvar, :mutex
61
+ #
62
+ # def initialize
63
+ # @condvar = ConditionVariable.new
64
+ # @mutex = Mutex.new
65
+ # end
66
+ #
67
+ # def wait(sec, &block)
68
+ # started = Time.now
69
+ # @mutex.synchronize do
70
+ # yield
71
+ # elapsed = (Time.now - started).to_f
72
+ # @condvar.wait(@mutex, sec - elapsed)
73
+ # end
74
+ # end
75
+ #
76
+ # def signal
77
+ # @condvar.signal
78
+ # end
79
+ end
80
+ end
@@ -0,0 +1,5 @@
1
+ module Triglav
2
+ module Agent
3
+ VERSION = "1.0.0.pre1"
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ module Triglav
2
+ module Agent
3
+ end
4
+ end
5
+
6
+ require 'triglav/agent/api_client'
7
+ require 'triglav/agent/configuration'
8
+ require 'triglav/agent/error'
9
+ require 'triglav/agent/hash_util'
10
+ require 'triglav/agent/logger'
11
+ require 'triglav/agent/storage_file'
12
+ require 'triglav/agent/timer'
13
+ require 'triglav/agent/version'
14
+
15
+ require 'triglav/agent/base/cli'
16
+ require 'triglav/agent/base/setting'
17
+ require 'triglav/agent/base/worker'
18
+ require 'triglav/agent/base/processor'
19
+ require 'triglav/agent/base/connection' # just a skelton
20
+ require 'triglav/agent/base/monitor' # just a skelton
@@ -0,0 +1 @@
1
+ require 'triglav/agent'
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'triglav/agent/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "triglav-agent"
8
+ spec.version = Triglav::Agent::VERSION
9
+ spec.authors = ["Triglav Team"]
10
+ spec.email = ["triglav_admin_my@dena.jp"]
11
+
12
+ spec.summary = %q{Framework of Triglav Agent in Ruby.}
13
+ spec.description = %q{Framework of Triglav Agent in Ruby.}
14
+ spec.homepage = "https://github.com/triglav-dataflow/triglav-agent-framework-ruby"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "serverengine"
23
+ spec.add_dependency "dotenv"
24
+ spec.add_dependency "triglav_client"
25
+ spec.add_dependency "parallel"
26
+ spec.add_dependency "connection_pool"
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.11"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "test-unit"
31
+ spec.add_development_dependency "test-unit-rr"
32
+ spec.add_development_dependency "yard"
33
+ end