ztk 0.3.1 → 1.0.0.rc.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.
@@ -0,0 +1,41 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Jove Labs
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ module ZTK::DSL::Core
22
+ module IO
23
+
24
+ def self.included(base)
25
+ base.class_eval do
26
+ base.send(:extend, ZTK::DSL::Core::IO::ClassMethods)
27
+ end
28
+ end
29
+
30
+ module ClassMethods
31
+
32
+ def load(rb_file)
33
+ new do
34
+ instance_eval(::IO.read(rb_file))
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,135 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Jove Labs
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ module ZTK::DSL::Core::Relations
22
+ module BelongsTo
23
+
24
+ def self.included(base)
25
+ base.class_eval do
26
+ base.add_relation(:belongs_to)
27
+ base.send(:extend, ZTK::DSL::Core::Relations::BelongsTo::ClassMethods)
28
+ end
29
+ end
30
+
31
+ def belongs_to_references
32
+ @belongs_to_references ||= {}
33
+ end
34
+
35
+ def get_belongs_to_reference(key)
36
+ logger.debug { "key(#{key})" }
37
+
38
+ if belongs_to_references.key?(key)
39
+ logger.debug { "found key -> (#{key})" }
40
+
41
+ belongs_to_references[key]
42
+ else
43
+ logger.debug { "looking up key -> (#{key})" }
44
+
45
+ key_id = send("#{key}_id")
46
+ item = key.to_s.classify.constantize.find(key_id).first
47
+ belongs_to_references[key] = item
48
+ end
49
+ end
50
+
51
+ def set_belongs_to_reference(key, value)
52
+ logger.debug { "key(#{key}), value(#{value})" }
53
+
54
+ belongs_to_references[key] = value
55
+ attributes.merge!("#{key}_id".to_sym => value.id)
56
+
57
+ klass = self.class.to_s.demodulize.downcase.pluralize
58
+ logger.debug { "send(#{klass})" }
59
+ many = value.send(klass)
60
+ many << self
61
+ many.uniq!
62
+ end
63
+
64
+ def save_belongs_to_references
65
+ belongs_to_references.each do |key, dataset|
66
+ dataset.each do |data|
67
+ # do something to store the data somewhere
68
+ end
69
+ end
70
+ end
71
+
72
+ module ClassMethods
73
+
74
+ def belongs_to(key, options={})
75
+ belongs_to_relations[key] = {
76
+ :class_name => key.to_s.classify,
77
+ :key => key
78
+ }.merge(options)
79
+ logger.debug { "key(#{key.inspect}), options(#{belongs_to_relations[key].inspect})" }
80
+
81
+ define_method(key) do |*args|
82
+ logger.debug { "*args(#{args.inspect})" }
83
+
84
+ if args.count == 0
85
+ get_belongs_to_reference(key)
86
+ else
87
+ send("#{key}=", *args)
88
+ end
89
+ end
90
+
91
+ define_method("#{key}=") do |value|
92
+ logger.debug { "#{key}= value(#{value.inspect})" }
93
+
94
+ set_belongs_to_reference(key, value)
95
+ end
96
+
97
+ define_method("#{key}_id") do |*args|
98
+ logger.debug { "#{key}_id *args(#{args.inspect})" }
99
+
100
+ if args.count == 0
101
+ attributes["#{key}_id".to_sym]
102
+ else
103
+ send("#{key}_id=".to_sym, args.first)
104
+ end
105
+
106
+ end
107
+
108
+ define_method("#{key}_id=") do |value|
109
+ options = self.class.belongs_to_relations[key]
110
+ logger.debug { "#{key}_id= value(#{value.inspect}), options(#{options.inspect})" }
111
+
112
+ if value != attributes["#{key}_id".to_sym]
113
+ item = options[:class_name].constantize.find(value).first
114
+ set_belongs_to_reference(key, item)
115
+ else
116
+ value
117
+ end
118
+ end
119
+
120
+ # define_method(singularize(key)) do |value|
121
+ # set_belongs_to_reference(key, value)
122
+ # end
123
+
124
+ # define_method(singularize(key)) do |&block|
125
+ # puts get_belongs_to_reference(key).inspect
126
+ # data = constantize(classify(key.to_s)).new(&block)
127
+ # get_belongs_to_reference(key) << data
128
+ # data
129
+ # end
130
+ end
131
+
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,105 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Jove Labs
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ module ZTK::DSL::Core::Relations
22
+ module HasMany
23
+
24
+ def self.included(base)
25
+ base.class_eval do
26
+ base.add_relation(:has_many)
27
+ base.send(:extend, ZTK::DSL::Core::Relations::HasMany::ClassMethods)
28
+ end
29
+ end
30
+
31
+ def has_many_references
32
+ @has_many_references ||= {}
33
+ end
34
+
35
+ def get_has_many_reference(key)
36
+ logger.debug { "key(#{key})" }
37
+
38
+ if has_many_references.key?(key)
39
+ logger.debug { "found key -> (#{key})" }
40
+
41
+ has_many_references[key]
42
+ else
43
+ logger.debug { "looking up key -> (#{key})" }
44
+
45
+ has_many_references[key] ||= []
46
+ end
47
+ end
48
+
49
+ def set_has_many_reference(key, value)
50
+ logger.debug { "key(#{key}), value(#{value})" }
51
+
52
+ dataset = get_has_many_reference(key)
53
+ dataset.clear
54
+ dataset.concat(value)
55
+ end
56
+
57
+ def save_has_many_references
58
+ has_many_references.each do |key, dataset|
59
+ dataset.each do |data|
60
+ # do something to store the data somewhere
61
+ end
62
+ end
63
+ end
64
+
65
+ module ClassMethods
66
+
67
+ def has_many(key, options={})
68
+ has_many_relations[key] = {
69
+ :class_name => key.to_s.classify,
70
+ :key => key
71
+ }.merge(options)
72
+ logger.debug { "key(#{key.inspect}), options(#{has_many_relations[key].inspect})" }
73
+
74
+ define_method(key) do |*args|
75
+ logger.debug { "#{key} *args(#{args.inspect})" }
76
+
77
+ if args.count == 0
78
+ get_has_many_reference(key)
79
+ else
80
+ send("#{key}=", *args)
81
+ end
82
+ end
83
+
84
+ define_method("#{key}=") do |value|
85
+ logger.debug { "#{key}= value(#{value.inspect})" }
86
+
87
+ set_has_many_reference(key, value)
88
+ end
89
+
90
+ define_method(key.to_s.singularize) do |&block|
91
+ options = self.class.has_many_relations[key]
92
+ logger.debug { "#{key.to_s.singularize} block(#{block.inspect}), options(#{options.inspect})" }
93
+ data = options[:class_name].constantize.new(&block)
94
+ get_has_many_reference(key) << data
95
+ klass = self.class.to_s.demodulize.singularize.downcase
96
+ logger.debug { "send(#{klass})" }
97
+ data.send("#{klass}=", self)
98
+ data
99
+ end
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,45 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Jove Labs
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ module ZTK::DSL::Core
22
+ module Relations
23
+ autoload :BelongsTo, "ztk/dsl/core/relations/belongs_to"
24
+ autoload :HasMany, "ztk/dsl/core/relations/has_many"
25
+
26
+ def self.included(base)
27
+ base.class_eval do
28
+ base.send(:extend, ZTK::DSL::Core::Relations::ClassMethods)
29
+ base.send(:include, ZTK::DSL::Core::Relations::BelongsTo)
30
+ base.send(:include, ZTK::DSL::Core::Relations::HasMany)
31
+ end
32
+ end
33
+
34
+ module ClassMethods
35
+
36
+ def add_relation(key)
37
+ relation_key = "#{key}_relations"
38
+ cattr_accessor relation_key
39
+ send(relation_key) || send("#{relation_key}=", {})
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,77 @@
1
+ module ZTK::DSL
2
+ module Core
3
+ autoload :Attributes, "ztk/dsl/core/attributes"
4
+ autoload :Actions, "ztk/dsl/core/actions"
5
+ autoload :Dataset, "ztk/dsl/core/dataset"
6
+ autoload :IO, "ztk/dsl/core/io"
7
+ autoload :Relations, "ztk/dsl/core/relations"
8
+
9
+ def self.included(base)
10
+ base.class_eval do
11
+ base.send(:extend, ZTK::DSL::Core::ClassMethods)
12
+
13
+ base.send(:extend, ZTK::DSL::Core::DualMethods)
14
+ base.send(:include, ZTK::DSL::Core::DualMethods)
15
+
16
+ base.send(:include, ZTK::DSL::Core::Attributes)
17
+ base.send(:include, ZTK::DSL::Core::Actions)
18
+ base.send(:include, ZTK::DSL::Core::Dataset)
19
+ base.send(:include, ZTK::DSL::Core::IO)
20
+ base.send(:include, ZTK::DSL::Core::Relations)
21
+ end
22
+ end
23
+
24
+ module DualMethods
25
+
26
+ def logger
27
+ unless defined?($logger)
28
+ $logger = ::ZTK::Logger.new("dsl.log")
29
+ $logger.info {"=" * 80}
30
+ $logger.info {"=" * 80}
31
+ $logger.info {"=" * 80}
32
+ end
33
+ $logger
34
+ end
35
+
36
+ end
37
+
38
+ module ClassMethods
39
+
40
+ def cattr_accessor(*args)
41
+ cattr_reader(*args)
42
+ cattr_writer(*args)
43
+ end
44
+
45
+ def cattr_reader(*args)
46
+ args.flatten.each do |arg|
47
+ next if arg.is_a?(Hash)
48
+ instance_eval %Q{
49
+ unless defined?(@@#{arg})
50
+ @@#{arg} = nil
51
+ end
52
+
53
+ def #{arg}
54
+ @@#{arg}
55
+ end
56
+ }
57
+ end
58
+ end
59
+
60
+ def cattr_writer(*args)
61
+ args.flatten.each do |arg|
62
+ next if arg.is_a?(Hash)
63
+ instance_eval %Q{
64
+ unless defined?(@@#{arg})
65
+ @@#{arg} = nil
66
+ end
67
+
68
+ def #{arg}=(value)
69
+ @@#{arg} = value
70
+ end
71
+ }
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+ end
data/lib/ztk/dsl.rb ADDED
@@ -0,0 +1,34 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Jove Labs
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ require "active_support/inflector"
22
+
23
+ # @author Zachary Patten <zachary@jovelabs.net>
24
+ module ZTK
25
+ module DSL
26
+
27
+ # @author Zachary Patten <zachary@jovelabs.net>
28
+ class DSLError < Error; end
29
+
30
+ autoload :Base, "ztk/dsl/base"
31
+ autoload :Core, "ztk/dsl/core"
32
+
33
+ end
34
+ end
data/lib/ztk/logger.rb CHANGED
@@ -17,7 +17,6 @@
17
17
  # limitations under the License.
18
18
  #
19
19
  ################################################################################
20
-
21
20
  require "logger"
22
21
 
23
22
  module ZTK
@@ -45,6 +44,7 @@ module ZTK
45
44
  # @author Zachary Patten <zachary@jovelabs.net>
46
45
  class Logger < ::Logger
47
46
 
47
+ # Log Levels
48
48
  SEVERITIES = Severity.constants.inject([]) {|arr,c| arr[Severity.const_get(c)] = c; arr}
49
49
 
50
50
  def initialize(*args)
@@ -52,15 +52,28 @@ module ZTK
52
52
  set_log_level
53
53
  end
54
54
 
55
+ # Provides access to the raw log device.
55
56
  def logdev
56
57
  self.instance_variable_get(:@logdev).instance_variable_get(:@dev)
57
58
  end
58
59
 
60
+ # Specialized logging. Logs messages in the same format, except has the
61
+ # option to shift the caller_at position to exposed the proper calling
62
+ # method.
63
+ #
64
+ # Very useful in situations of class inheritence, for example, where you
65
+ # might have logging statements in a base class, which are inherited by
66
+ # another class. When calling the base class method via the inherited class
67
+ # the log messages will indicate the base class as the caller. While this
68
+ # is technically true it is not always what we want to see in the logs
69
+ # because it is ambigious and does not show us where the call truly
70
+ # originated from.
59
71
  def shift(severity, shift=0, &block)
60
72
  severity = ZTK::Logger.const_get(severity.to_s.upcase)
61
73
  add(severity, nil, nil, shift, &block)
62
74
  end
63
75
 
76
+ # Generates a human-readable string about the logger.
64
77
  def inspect
65
78
  "#<#{self.class} filename=#{@logdev.filename.inspect}>"
66
79
  end
data/lib/ztk/parallel.rb CHANGED
@@ -17,7 +17,6 @@
17
17
  # limitatIOns under the License.
18
18
  #
19
19
  ################################################################################
20
-
21
20
  require "base64"
22
21
 
23
22
  module ZTK
@@ -62,6 +61,7 @@ module ZTK
62
61
  # @author Zachary Patten <zachary@jovelabs.net>
63
62
  class Parallel < ZTK::Base
64
63
 
64
+ # Default Maximum Number of Forks
65
65
  MAX_FORKS = case RUBY_PLATFORM
66
66
  when /darwin/ then
67
67
  %x( sysctl hw.ncpu ).chomp.split(':').last.strip.to_i
@@ -72,7 +72,7 @@ module ZTK
72
72
  # Result Set
73
73
  attr_accessor :results
74
74
 
75
- # @param [Hash] config Configuration options hash.
75
+ # @param [Hash] configuration Configuration options hash.
76
76
  # @option config [Integer] :max_forks Maximum number of forks to use.
77
77
  # @option config [Proc] :before_fork (nil) Proc to call before forking.
78
78
  # @option config [Proc] :after_fork (nil) Proc to call after forking.
data/lib/ztk/report.rb CHANGED
@@ -17,7 +17,6 @@
17
17
  # limitations under the License.
18
18
  #
19
19
  ################################################################################
20
-
21
20
  require 'socket'
22
21
  require 'timeout'
23
22
 
@@ -28,6 +27,15 @@ module ZTK
28
27
  # @author Zachary Patten <zachary@jovelabs.net>
29
28
  class ReportError < Error; end
30
29
 
30
+ # ZTK Report Class
31
+ #
32
+ # This class contains tools for generating spreadsheet or key-value list
33
+ # styled output. Report methods are currently meant to be interchangeable;
34
+ # that is one should be able to just switch which method they are calling
35
+ # to change the output type.
36
+ #
37
+ # The idea here is that everything is auto-sized and simply displayed.
38
+ #
31
39
  # @author Zachary Patten <zachary@jovelabs.net>
32
40
  class Report < ZTK::Base
33
41
 
@@ -38,6 +46,21 @@ module ZTK
38
46
  config.logger.debug { "config=#{config.send(:table).inspect}" }
39
47
  end
40
48
 
49
+ # Displays data in a spreadsheet style.
50
+ #
51
+ # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+
52
+ # | NAME | ALIVE | ARCH | DISTRO | IP | MAC | CHEF VERSION | PERSIST |
53
+ # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+
54
+ # | sudo | false | amd64 | ubuntu | 192.168.99.110 | 00:00:5e:34:d6:aa | N/A | true |
55
+ # | timezone | false | amd64 | ubuntu | 192.168.122.47 | 00:00:5e:92:d7:f6 | N/A | true |
56
+ # | chef-client | false | amd64 | ubuntu | 192.168.159.98 | 00:00:5e:c7:ce:26 | N/A | true |
57
+ # | users | false | amd64 | ubuntu | 192.168.7.78 | 00:00:5e:89:f9:50 | N/A | true |
58
+ # +-------------+-------+-------+--------+----------------+-------------------+--------------+---------+
59
+ #
60
+ # @param [Array] dataset An array of items for which we want to generate a
61
+ # report
62
+ # @param [Array] headers An array of headers used for ordering the output.
63
+ # @return [OpenStruct]
41
64
  def spreadsheet(dataset, headers, &block)
42
65
  !block_given? and log_and_raise(ReportError, "You must supply a block!")
43
66
  headers.nil? and log_and_raise(ReportError, "Headers can not be nil!")
@@ -80,6 +103,25 @@ module ZTK
80
103
  OpenStruct.new(:rows => rows, :max_lengths => max_lengths, :width => width)
81
104
  end
82
105
 
106
+ # Displays data in a key-value list style.
107
+ #
108
+ # +-------------------------------------------------------------------+
109
+ # | PROVIDER: Cucumber::Chef::Provider::Vagrant |
110
+ # | ID: default |
111
+ # | STATE: aborted |
112
+ # | USERNAME: vagrant |
113
+ # | IP ADDRESS: 127.0.0.1 |
114
+ # | PORT: 2222 |
115
+ # | CHEF-SERVER API: http://127.0.0.1:4000 |
116
+ # | CHEF-SERVER WEBUI: http://127.0.0.1:4040 |
117
+ # | CHEF-SERVER DEFAULT USER: admin |
118
+ # | CHEF-SERVER DEFAULT PASSWORD: p@ssw0rd1 |
119
+ # +-------------------------------------------------------------------+
120
+ #
121
+ # @param [Array] dataset An array of items for which we want to generate a
122
+ # report
123
+ # @param [Array] headers An array of headers used for ordering the output.
124
+ # @return [OpenStruct]
83
125
  def list(dataset, headers, &block)
84
126
  !block_given? and log_and_raise(ReportError, "You must supply a block!")
85
127
  headers.nil? and log_and_raise(ReportError, "Headers can not be nil!")
@@ -17,6 +17,7 @@
17
17
  # limitations under the License.
18
18
  #
19
19
  ################################################################################
20
+
20
21
  module ZTK
21
22
 
22
23
  # ZTK::RescueRetry Error Class
@@ -24,13 +25,50 @@ module ZTK
24
25
  # @author Zachary Patten <zachary@jovelabs.net>
25
26
  class RescueRetryError < Error; end
26
27
 
27
- # RescueRetry Class
28
+ # ZTK RescueRetry Class
29
+ #
30
+ # This class contains an exception handling tool, which will allowing retry
31
+ # of all or specific *Exceptions* based on a set number of attempts to make.
32
+ #
33
+ # The block is yielded and if a valid exception occurs the block will be
34
+ # re-executed for the set number of attempts.
35
+ #
36
+ # For example, from the ZTK SSH class:
37
+ #
38
+ # ZTK::RescueRetry.try(:tries => 3, :on => EOFError) do
39
+ # @ssh = Net::SSH.start(config.host_name, config.user, ssh_options)
40
+ # ...
41
+ # end
42
+ #
43
+ # If an SSH connection drops on the other side and we go to write to it, we
44
+ # will get this error. Wrapping the SSH code in *RescueRetry* allows us to
45
+ # retry the connection in the event this happens. If we have no luck after
46
+ # 3 attempts at executing the block, *RescueRetry* surfaces the exception.
28
47
  #
29
48
  # @author Zachary Patten <zachary@jovelabs.net>
30
49
  class RescueRetry
31
50
 
32
51
  class << self
33
52
 
53
+ # Rescue and Retry the supplied block.
54
+ #
55
+ # When no options are supplied, if an *Exception* is encounter it is
56
+ # surfaced immediately and no retry is performed.
57
+ #
58
+ # It is advisable to at least leave the *delay* option at 1. You could
59
+ # optionally set this to 0, but this is generally a bad idea.
60
+ #
61
+ # @param [Hash] options Configuration options hash.
62
+ # @option options [String] :tries (1) How many attempts at executing the
63
+ # block before we give up and surface the *Exception*.
64
+ # @option options [String] :on (Exception) Watch for a specific exception
65
+ # instead of performing retry on all exceptions.
66
+ # @option options [Float,Integer] :delay (1) How long to sleep for between
67
+ # each retry.
68
+ #
69
+ # @yield Block should execute the tasks to be rescued and retried if
70
+ # needed.
71
+ # @return [Object] The return value of the block.
34
72
  def try(options={}, &block)
35
73
  options = Base.build_config({
36
74
  :tries => 1,