emissary 1.3.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,106 @@
1
+ # Copyright 2010 The New York Times
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ #
16
+ module Emissary
17
+
18
+ class Error< StandardError
19
+ class ConnectionError < StandardError; end
20
+ class InvalidMessageFormat < StandardError; end
21
+ class NotImplementedError < StandardError; end
22
+
23
+ attr_reader :origin
24
+
25
+ def self.new(*args) #:nodoc:
26
+ allocate.instance_eval(<<-EOS, __FILE__, __LINE__)
27
+ alias :original_instance_of? :instance_of?
28
+ alias :original_kind_of? :kind_of?
29
+
30
+ def instance_of? klass
31
+ self.original_instance_of? klass or origin.instance_of? klass
32
+ end
33
+
34
+ def kind_of? klass
35
+ self.original_kind_of? klass or origin.kind_of? klass
36
+ end
37
+
38
+ # Call a superclass's #initialize if it has one
39
+ initialize(*args)
40
+
41
+ self
42
+ EOS
43
+ end
44
+
45
+ def initialize(origin = Exception, message = '')
46
+
47
+ case origin
48
+ when Exception
49
+ @origin = origin
50
+ when Class
51
+ @origin = origin.new message
52
+ else
53
+ @origin = Exception.new message
54
+ end
55
+
56
+ super message
57
+ end
58
+
59
+ def origin_backtrace
60
+ origin.backtrace
61
+ end
62
+
63
+ def origin_message
64
+ origin.message
65
+ end
66
+
67
+ def message
68
+ "#{super}\n\t#{self.backtrace.join("\n\t")}\n" +
69
+ "Origin: #{origin.class}: #{origin_message}\n\t#{origin_backtrace.join("\n\t")}"
70
+ end
71
+ end
72
+ end
73
+
74
+ if __FILE__ == $0
75
+ class Emissary::TrackingError < Emissary::Error; end
76
+ class Emissary::NetworkEncapsulatedError < Emissary::Error; end
77
+ def a() raise ArgumentError, 'testing'; end
78
+ def b() a; end
79
+ def c() b; end
80
+ def d() c; end
81
+ def test() d; end
82
+
83
+ begin
84
+ begin
85
+ begin
86
+ begin
87
+ test
88
+ rescue Exception => e
89
+ raise Emissary::Error.new e, 'general error'
90
+ end
91
+ rescue Emissary::Error => e
92
+ puts "----------------- 1 -----------------\n#{e.message}"
93
+ raise Emissary::TrackingError.new(e, 'testing tracking')
94
+ end
95
+ rescue Emissary::Error => e
96
+ puts "----------------- 2 -----------------\n#{e.message}"
97
+ raise Emissary::NetworkEncapsulatedError.new(e, 'testing network encapsulated')
98
+ end
99
+ rescue Emissary::Error => e
100
+ puts "----------------- 3 -----------------\n#{e.message}"
101
+ end
102
+
103
+ [ Exception, ArgumentError, Emissary::Error, Emissary::TrackingError, Emissary::NetworkEncapsulatedError].each do |k|
104
+ puts "e.kind_of?(#{k.name}): #{e.kind_of? k}"
105
+ end
106
+ end
@@ -0,0 +1,183 @@
1
+ # Copyright 2010 The New York Times
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ #
16
+ require 'rubygems/spec_fetcher'
17
+ require 'rubygems/dependency_installer'
18
+ require 'rubygems/uninstaller'
19
+
20
+ module Emissary
21
+ class GemHelper
22
+ attr_reader :name, :version
23
+
24
+ def initialize(name)
25
+ @name = name
26
+ @version = current_version
27
+ end
28
+
29
+ def version
30
+ (v = @version.to_s.delete('<>!=~ ').strip).empty? ? 0 : v
31
+ end
32
+
33
+ def normalize_version value
34
+ case value
35
+ when Gem::Requirement, Gem::Version
36
+ value
37
+
38
+ when /^(<|<=|=|!=|>|>=|~>)\s*[0-9.]+$/
39
+ Gem::Requirement.new value
40
+
41
+ when /^[0-9.]+$/, String, Fixnum
42
+ Gem::Version.new value
43
+
44
+ when :current
45
+ Gem::Version.new(self.version)
46
+
47
+ when :all, :any, :installed, :available
48
+ Gem::Requirement.default
49
+
50
+ when :newer_than_me, :latest, :newest
51
+ Gem::Requirement.new "> #{self.version}"
52
+
53
+ when :older_than_me
54
+ Gem::Requirement.new "< #{self.version}"
55
+ end
56
+ end
57
+
58
+ def updateable?
59
+ installed? && !versions(:newer_than_me).empty?
60
+ end
61
+
62
+ def is_a_provider? version = :current
63
+ return false unless (spec = Gem.source_index.find_name(@name, normalize_version(version)).first)
64
+ !Gem::DependencyList.from_source_index(Gem.source_index).ok_to_remove?(spec.full_name)
65
+ end
66
+ alias :have_dependents? :is_a_provider?
67
+ alias :has_dependents? :is_a_provider?
68
+
69
+ def removable? version = :current, ignore_dependents = false
70
+ installed?(version) && (!!ignore_dependents || !have_dependents?(version))
71
+ end
72
+
73
+ def installable? version = :any
74
+ !versions(:any).empty? && !installed?(version) && normalize_version(version) > @version
75
+ end
76
+
77
+ def installed? version = :any
78
+ !Gem.source_index.search(Gem::Dependency.new(name, normalize_version(version))).empty?
79
+ end
80
+
81
+ def current_version
82
+ return Gem::Version.new(0) unless installed?
83
+ specs = Gem.source_index.search(Gem::Dependency.new(name, normalize_version(:newest)))
84
+ specs.map { |spec| spec.version }.sort{ |a,b| a <=> b }.first
85
+ end
86
+
87
+ def versions which = :all
88
+ # don't include others for latest/newest - do include otherwise
89
+ others = [:latest, :newest ].include?(which) ? false : true
90
+ dependency = Gem::Dependency.new(name, normalize_version(which))
91
+ list = Gem::SpecFetcher.fetcher.find_matching(dependency, others).map do |spec, source_uri|
92
+ _, version = spec
93
+ [version, source_uri]
94
+ end.sort { |a,b| b[0] <=> a[0] }
95
+
96
+ which != :installed ? list : list.select { |v| installed? v[0] }
97
+ end
98
+
99
+ def dependents version = :current
100
+ specs = Gem.source_index.find_name(@name, normalize_version(version))
101
+ specs.inject([]) do |list,spec|
102
+ list |= spec.dependent_gems
103
+ list
104
+ end
105
+ end
106
+
107
+ def install version = :latest, source = :default
108
+ return @version unless installable? version
109
+
110
+ source = URI.parse(source).to_s rescue :default
111
+
112
+ options = {}
113
+ options[:version], source_uri = case version
114
+ when :latest
115
+ ver, uri = versions(:newer_than_me).first
116
+ [ ver, source == :default ? uri : source ]
117
+ else
118
+ ver, uri = versions(:newer_than_me).select { |v| v[0] == normalize_version(version) }.flatten
119
+ [ ver, source == :default ? uri : source ]
120
+ end
121
+
122
+ raise ArgumentError, "Bad version '#{version.inspect}' - can't install specified version." unless options[:version]
123
+
124
+ with_gem_source(source_uri) do
125
+ installer = Gem::DependencyInstaller.new options
126
+ installer.install name, options[:version]
127
+ @version = Gem::Version.new(normalize_version(options[:version]).to_s.delete('<>!=~ '))
128
+ end
129
+ end
130
+
131
+ def update version = :latest, source = :default, keep_old = true
132
+ return false unless updateable?
133
+ uninstall(@version, false) unless keep_old
134
+ install version, source
135
+ end
136
+
137
+ def uninstall version = :current, ignore_deps = false, remove_execs = false
138
+ options = {}
139
+ options[:ignore] = !!ignore_deps
140
+ options[:executables] = !!remove_execs
141
+
142
+ options[:version] = case version
143
+ when :current
144
+ @version
145
+ when :all
146
+ options[:all] = true
147
+ Gem::Requirement.default
148
+ else
149
+ versions(:all).select { |v| v[0] == normalize_version(version) }.flatten[0]
150
+ end
151
+
152
+ return true if not installed? version
153
+ raise ArgumentError, "Cannot uninstall version #{version.inspect} - is it installed? [#{options.inspect}]" unless options[:version]
154
+
155
+ unless removable?(version, !!ignore_deps)
156
+ msg = ['Refusing to uninstall gem required by other gems:']
157
+ dependents(options[:version]).each do |gem, dep, satlist|
158
+ msg << " Gem '#{gem.name}-#{gem.version}' depends on '#{dep.name}' (#{dep.requirement})";
159
+ end
160
+ raise Exception, msg.join("\n")
161
+ end
162
+
163
+ Gem::Uninstaller.new(name, options).uninstall
164
+ Gem.refresh
165
+ @version = Gem::Version.new '0'
166
+ end
167
+ alias :remove :uninstall
168
+
169
+ private
170
+
171
+ def with_gem_source(source)
172
+ begin
173
+ original_sources = Gem.sources.dup
174
+ Gem.sources.replace [source]
175
+ return yield
176
+ ensure
177
+ Gem.sources.replace original_sources
178
+ Gem.refresh
179
+ end
180
+ end
181
+ end
182
+
183
+ end
@@ -0,0 +1,183 @@
1
+ # Copyright 2010 The New York Times
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ #
16
+ require 'net/http'
17
+ require 'socket'
18
+
19
+ module Emissary
20
+ class Identity
21
+
22
+ INTERNAL_IDENTITY_GLOB = ::File.join(Emissary::LIBPATH, 'emissary', 'identity', '*.rb')
23
+ EXTERNAL_IDENTITY_GLOB = ::File.join(Emissary::EXTERNAL_IDENTITIES, '*.rb')
24
+
25
+ attr_reader :loaded, :methods
26
+ alias :loaded? :loaded
27
+
28
+ private :initialize
29
+
30
+ def initialize
31
+ @loaded = false
32
+ @methods = nil
33
+ @identities = nil
34
+ end
35
+
36
+ def self.instance
37
+ @@instance ||= self.new
38
+ end
39
+
40
+ def self.new(*largs)
41
+ # prevent subclasses from being instantiated directly, except through
42
+ # the identities() method of this parent class. This class is just a
43
+ # simple method factory and the children shouldn't need to be accessed
44
+ # except through the interface provided here.
45
+ if self == Emissary::Identity
46
+ raise Exception, "Cannot instantiate singleton class directly - use #{self.name}#instance" unless __caller__ == :instance
47
+ else
48
+ klass = self.name.split(/::/)[0..-2].join '::'; subklass = self.name.split(/::/).last
49
+ raise Exception, "Cannot instantiate '#{klass}' subclass '#{subklass}' directly" unless __caller__ == :identities
50
+ end
51
+
52
+ allocate.instance_eval(<<-EOS, __FILE__, __LINE__)
53
+ load_identities unless self.class != Emissary::Identity
54
+ self
55
+ EOS
56
+ end
57
+
58
+ # Delegation Factory - Uses registered high priority subclasses
59
+ # for delegation of method calls, falling back to lower priority
60
+ # subclasess when the method isn't available or throws a :pass
61
+ # in the higher priority subclass
62
+ #
63
+ def method_missing name, *args
64
+ # don't perform lookups on subclasses
65
+ super name, *args unless self.class == Emissary::Identity
66
+
67
+ name = name.to_sym
68
+ unless (@methods||={}).has_key? name
69
+ method_delegate = value = nil
70
+
71
+ # loop through each possible identity, higher priority identities
72
+ # first (0 == low, > 0 == higher).
73
+ identities.each do |id,object|
74
+ value = nil
75
+ if object.respond_to?(name)
76
+ method_delegate = catch(:pass) {
77
+ value = object.__send__(name, *args) # test for :pass request
78
+ object
79
+ }
80
+ break unless method_delegate.nil?
81
+ end
82
+ end
83
+
84
+ # if we've gone through all the possible delegates, then pass it
85
+ # up to the superclass (in this case, Object)
86
+ if method_delegate.nil?
87
+ return super(name, *args)
88
+ end
89
+
90
+ @methods[name] = method_delegate
91
+ return value
92
+ end
93
+
94
+ return @methods[name].__send__(name, *args)
95
+ end
96
+
97
+ def self.register name, opts = {}
98
+ priority = if name != :unix
99
+ opts[:priority].to_i > 0 ? opts.delete(:priority).to_i : 1
100
+ else
101
+ # unix identity always gets zero - though this locks us
102
+ # into *nix as our base. XXX maybe rethink this?
103
+ 0
104
+ end
105
+
106
+ (self.registry[priority] ||= []) << name
107
+ end
108
+
109
+ def self.exclude names
110
+ @@exclusions ||= []
111
+ @@exclusions |= (names.is_a?(String) ? names.split(/\s*,\s*/) : names.to_a.collect { |n| n.to_s.to_sym })
112
+ end
113
+
114
+ # Exclude an identity type when delegating identity method calls
115
+ #
116
+ def self.exclusions
117
+ @@exclusions ||= []
118
+ @@exclusions.to_a.map! { |e| e.to_sym }
119
+ end
120
+
121
+ def to_s
122
+ s = ''
123
+ s << '#<%s:0x%x ' % [ self.class, self.__id__ * 2]
124
+ s << to_h.inject([]) { |a,(k,v)| a << %Q|@#{k}="#{v}"| }.join(', ')
125
+ s << '>'
126
+ end
127
+
128
+ # Retrieve a list of all the available identifers through reflection of the subclasses
129
+ #
130
+ def identifiers
131
+ identities.inject([]) do |list,(id,object)|
132
+ list |= object.public_methods - object.class.superclass.public_methods - self.public_methods; list
133
+ end.sort.collect { |id| id.to_sym }
134
+ end
135
+
136
+ # Retreive a hash of all identifiers and their values
137
+ #
138
+ def to_h
139
+ Hash[(identifiers).zip(identifiers.collect { |identifier| self.send(identifier) })]
140
+ end
141
+
142
+ private
143
+
144
+ def self.registry
145
+ @@registry ||= []
146
+ end
147
+
148
+ # Loads all available identities included with this gem
149
+ #
150
+ def load_identities
151
+ return unless not !!loaded?
152
+
153
+ Dir[INTERNAL_IDENTITY_GLOB, EXTERNAL_IDENTITY_GLOB].reject do |id|
154
+ self.class.exclusions.include?("/#{id.to_s.downcase}.rb")
155
+ end.each do |file|
156
+ ::Emissary.logger.info "Loading Identity: #{file}"
157
+ require File.expand_path(file)
158
+ end
159
+
160
+ @loaded = true
161
+ end
162
+
163
+ # Generates list of possible identities after removing registered exclusions
164
+ # and then ordering them highest priority (> 0) to lowest priority (== 0)
165
+ #
166
+ def identities
167
+ @@identities ||= begin
168
+ self.class.registry.reverse.flatten.reject do |id|
169
+ id.nil? || self.class.exclusions.include?(id)
170
+ end.inject([]) do |a,id|
171
+ a << [ id.to_s, ::Emissary.klass_const("Emissary::Identity::#{id.to_s.capitalize}").new ]; a
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ if __FILE__ == $0
179
+ puts "-----> Name: " + (Emissary.identity.name rescue 'Could not acquire name')
180
+ puts "-----> P IP: " + (Emissary.identity.public_ip rescue 'Could not acquire public ip')
181
+ puts "-----> L IP: " + (Emissary.identity.local_ip rescue 'Could not acquire local_ip')
182
+ puts "-- Identity: " + (Emissary.identity.to_s rescue 'identity not set...')
183
+ end