circus-deployment 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/LICENSE +23 -0
  2. data/README.md +0 -0
  3. data/bin/circus +24 -0
  4. data/lib/bundler/circus_bundler.rb +24 -0
  5. data/lib/bundler/circus_util.rb +43 -0
  6. data/lib/bundler/patches.rb +18 -0
  7. data/lib/circus/act.rb +74 -0
  8. data/lib/circus/actstore_client.rb +30 -0
  9. data/lib/circus/agents/agent.rb +59 -0
  10. data/lib/circus/agents/client.rb +77 -0
  11. data/lib/circus/agents/connection.rb +76 -0
  12. data/lib/circus/agents/conversation.rb +17 -0
  13. data/lib/circus/agents/dbus_connection.rb +85 -0
  14. data/lib/circus/agents/dbus_logger.rb +34 -0
  15. data/lib/circus/agents/encoding.rb +32 -0
  16. data/lib/circus/agents/logger.rb +52 -0
  17. data/lib/circus/agents/params.rb +47 -0
  18. data/lib/circus/agents/ssh_connection.rb +120 -0
  19. data/lib/circus/application.rb +99 -0
  20. data/lib/circus/booth_client.rb +25 -0
  21. data/lib/circus/booth_tool.rb +98 -0
  22. data/lib/circus/cli.rb +147 -0
  23. data/lib/circus/clown_client.rb +27 -0
  24. data/lib/circus/connection_builder.rb +32 -0
  25. data/lib/circus/external_util.rb +14 -0
  26. data/lib/circus/local_config.rb +65 -0
  27. data/lib/circus/profiles/base.rb +115 -0
  28. data/lib/circus/profiles/django.rb +90 -0
  29. data/lib/circus/profiles/jekyll.rb +90 -0
  30. data/lib/circus/profiles/make_base.rb +17 -0
  31. data/lib/circus/profiles/pure_py.rb +46 -0
  32. data/lib/circus/profiles/pure_rb.rb +48 -0
  33. data/lib/circus/profiles/python_base.rb +39 -0
  34. data/lib/circus/profiles/rack.rb +59 -0
  35. data/lib/circus/profiles/ruby_base.rb +52 -0
  36. data/lib/circus/profiles/shell.rb +46 -0
  37. data/lib/circus/profiles.rb +10 -0
  38. data/lib/circus/repos/git.rb +42 -0
  39. data/lib/circus/repos/mercurial.rb +42 -0
  40. data/lib/circus/repos.rb +16 -0
  41. data/lib/circus/resource_allocator_client.rb +19 -0
  42. data/lib/circus/stdout_logger.rb +11 -0
  43. data/lib/circus/version.rb +3 -0
  44. data/lib/circus.rb +9 -0
  45. data/vendor/ruby-dbus/COPYING +504 -0
  46. data/vendor/ruby-dbus/ChangeLog +782 -0
  47. data/vendor/ruby-dbus/HOWTO-RELEASE +14 -0
  48. data/vendor/ruby-dbus/NEWS +104 -0
  49. data/vendor/ruby-dbus/README +53 -0
  50. data/vendor/ruby-dbus/Rakefile +47 -0
  51. data/vendor/ruby-dbus/doc/tutorial/src/00.index.page +12 -0
  52. data/vendor/ruby-dbus/doc/tutorial/src/10.intro.page +127 -0
  53. data/vendor/ruby-dbus/doc/tutorial/src/20.basic_client.page +174 -0
  54. data/vendor/ruby-dbus/doc/tutorial/src/30.service.page +121 -0
  55. data/vendor/ruby-dbus/doc/tutorial/src/default.css +129 -0
  56. data/vendor/ruby-dbus/doc/tutorial/src/default.template +46 -0
  57. data/vendor/ruby-dbus/examples/gdbus/gdbus +255 -0
  58. data/vendor/ruby-dbus/examples/gdbus/gdbus.glade +184 -0
  59. data/vendor/ruby-dbus/examples/gdbus/launch.sh +4 -0
  60. data/vendor/ruby-dbus/examples/no-introspect/nm-test.rb +21 -0
  61. data/vendor/ruby-dbus/examples/no-introspect/tracker-test.rb +16 -0
  62. data/vendor/ruby-dbus/examples/rhythmbox/playpause.rb +25 -0
  63. data/vendor/ruby-dbus/examples/service/call_service.rb +25 -0
  64. data/vendor/ruby-dbus/examples/service/service_newapi.rb +51 -0
  65. data/vendor/ruby-dbus/examples/simple/call_introspect.rb +34 -0
  66. data/vendor/ruby-dbus/examples/utils/listnames.rb +11 -0
  67. data/vendor/ruby-dbus/examples/utils/notify.rb +19 -0
  68. data/vendor/ruby-dbus/lib/dbus/auth.rb +156 -0
  69. data/vendor/ruby-dbus/lib/dbus/bus.rb +750 -0
  70. data/vendor/ruby-dbus/lib/dbus/export.rb +133 -0
  71. data/vendor/ruby-dbus/lib/dbus/introspect.rb +544 -0
  72. data/vendor/ruby-dbus/lib/dbus/marshall.rb +443 -0
  73. data/vendor/ruby-dbus/lib/dbus/matchrule.rb +100 -0
  74. data/vendor/ruby-dbus/lib/dbus/message.rb +293 -0
  75. data/vendor/ruby-dbus/lib/dbus/type.rb +222 -0
  76. data/vendor/ruby-dbus/lib/dbus.rb +89 -0
  77. data/vendor/ruby-dbus/ruby-dbus.gemspec +28 -0
  78. data/vendor/ruby-dbus/setup.rb +1585 -0
  79. data/vendor/ruby-dbus/test/Makefile +4 -0
  80. data/vendor/ruby-dbus/test/bus_driver_test.rb +21 -0
  81. data/vendor/ruby-dbus/test/server_robustness_test.rb +41 -0
  82. data/vendor/ruby-dbus/test/server_test.rb +44 -0
  83. data/vendor/ruby-dbus/test/service_newapi.rb +99 -0
  84. data/vendor/ruby-dbus/test/session_bus_test_manual.rb +20 -0
  85. data/vendor/ruby-dbus/test/signal_test.rb +57 -0
  86. data/vendor/ruby-dbus/test/t1 +4 -0
  87. data/vendor/ruby-dbus/test/t2.rb +66 -0
  88. data/vendor/ruby-dbus/test/t3-ticket27.rb +18 -0
  89. data/vendor/ruby-dbus/test/t5-report-dbus-interface.rb +58 -0
  90. data/vendor/ruby-dbus/test/t6-loop.rb +85 -0
  91. data/vendor/ruby-dbus/test/test_all +26 -0
  92. data/vendor/ruby-dbus/test/test_server +74 -0
  93. data/vendor/ruby-dbus/test/variant_test.rb +66 -0
  94. metadata +225 -0
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ ## Software License
2
+ > Copyright (c) 2009-2010 Paul Jones <pauljones23@gmail.com>
3
+ > Copyright (c) 2009-2010 LShift Ltd. <query@lshift.net>
4
+ >
5
+ > Permission is hereby granted, free of charge, to any person
6
+ > obtaining a copy of this software and associated documentation
7
+ > files (the "Software"), to deal in the Software without
8
+ > restriction, including without limitation the rights to use, copy,
9
+ > modify, merge, publish, distribute, sublicense, and/or sell copies
10
+ > of the Software, and to permit persons to whom the Software is
11
+ > furnished to do so, subject to the following conditions:
12
+ >
13
+ > The above copyright notice and this permission notice shall be
14
+ > included in all copies or substantial portions of the Software.
15
+ >
16
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ > NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ > HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ > WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
+ > DEALINGS IN THE SOFTWARE.
data/README.md ADDED
File without changes
data/bin/circus ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ # Circus command line interface script.
3
+ # Run <tt>circus -h</tt> to get more usage.
4
+
5
+ # If we can see a Gemfile, then we're in dev and should use it
6
+ if File.exists?(File.expand_path('../../Gemfile', __FILE__))
7
+ ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
8
+ begin
9
+ # Try to require the preresolved locked set of gems.
10
+ require File.expand_path('../../.bundle/environment', __FILE__)
11
+ rescue LoadError
12
+ # Fall back on doing an unlocked resolve at runtime.
13
+ require "rubygems"
14
+ require "bundler"
15
+ Bundler.setup
16
+ end
17
+ end
18
+
19
+ $: << File.expand_path('../../lib', __FILE__)
20
+ $: << File.expand_path('../../vendor/ruby-dbus/lib', __FILE__)
21
+ require File.expand_path('../../lib/circus', __FILE__)
22
+ require File.expand_path('../../lib/circus/cli', __FILE__)
23
+
24
+ Circus::CLI.start
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Circus specific entry-point for bundler that handles the packaging of gems for an application.
4
+ require 'rubygems'
5
+ require 'bundler'
6
+ require 'bundler/cli'
7
+ require File.expand_path('../patches', __FILE__)
8
+ require File.expand_path('../circus_util', __FILE__)
9
+
10
+ class LoggingShell
11
+ def say(msg)
12
+ puts msg
13
+ end
14
+ end
15
+
16
+ # Run the bundler install
17
+ dir = File.expand_path('.')
18
+ ENV['BUNDLE_GEMFILE'] = File.join(dir, 'Gemfile')
19
+ Bundler.settings[:path] = 'vendor'
20
+ Bundler.ui = Bundler::UI::Shell.new(LoggingShell.new)
21
+ Gem::DefaultUserInteraction.ui = Bundler::UI::RGProxy.new(Bundler.ui)
22
+ Bundler::Installer.install(Bundler.root, Bundler.definition, {})
23
+
24
+ Bundler::CircusUtil.fix_external_paths(dir)
@@ -0,0 +1,43 @@
1
+ require 'bundler'
2
+
3
+ module Bundler
4
+ class CircusUtil
5
+ def self.fix_external_paths(dir)
6
+ ENV['BUNDLE_GEMFILE'] = File.join(dir, 'Gemfile')
7
+
8
+ # Correct any path based components in the Gemfile
9
+ full_dir = File.expand_path(dir)
10
+ gem_cache_dir = File.join(dir, 'vendor', 'gems')
11
+ definition = Bundler.definition
12
+ required_updates = []
13
+ definition.sources.select { |s| s.is_a? Bundler::Source::Path }.each do |p|
14
+ unless p.path.to_s.start_with? full_dir
15
+ FileUtils.mkdir_p(gem_cache_dir)
16
+ FileUtils.cp_r(p.path, File.join(gem_cache_dir, p.path.basename.to_s))
17
+
18
+ if p.is_a? Bundler::Source::Git
19
+ required_updates << {:old => /git .*#{p.uri}.*/, :new => "path \"vendor/gems/#{p.path.basename.to_s}\""}
20
+ else
21
+ required_updates << {:old => p.options['path'], :new => "vendor/gems/#{p.path.basename.to_s}"}
22
+ end
23
+ end
24
+ end
25
+ if required_updates.length > 0
26
+ FileUtils.cp "#{dir}/Gemfile", "#{dir}/Gemfile.circus_orig"
27
+ gf_content = File.read("#{dir}/Gemfile")
28
+ required_updates.each do |u|
29
+ gf_content.gsub!(u[:old], u[:new])
30
+ end
31
+ File.open("#{dir}/Gemfile", 'w') do |f|
32
+ f.write(gf_content)
33
+ end
34
+ end
35
+ end
36
+
37
+ def self.unfix_external_paths(dir)
38
+ if File.exists? "#{dir}/Gemfile.circus_orig"
39
+ FileUtils.mv "#{dir}/Gemfile.circus_orig", "#{dir}/Gemfile"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,18 @@
1
+ #module Bundler
2
+ # class Environment
3
+ #def write_rb_lock
4
+ # Disabled
5
+ #end
6
+ # end
7
+ #end
8
+
9
+ module Bundler
10
+ module Source
11
+ # Disable the use of System Gems
12
+ class SystemGems
13
+ def specs
14
+ []
15
+ end
16
+ end
17
+ end
18
+ end
data/lib/circus/act.rb ADDED
@@ -0,0 +1,74 @@
1
+ require 'fileutils'
2
+ require 'yaml'
3
+
4
+ module Circus
5
+ class Act
6
+ attr_reader :name, :dir, :props, :profile
7
+
8
+ def initialize(name, dir, props = {})
9
+ @name = name
10
+ @dir = dir
11
+ @props = props
12
+
13
+ # Merge act specific properties
14
+ if File.exists? act_file
15
+ act_cfg = YAML.load(File.read(act_file))
16
+ @props.merge! act_cfg
17
+ end
18
+ end
19
+
20
+ def should_package?
21
+ return false if @props['no-package']
22
+ true
23
+ end
24
+
25
+ def detect!
26
+ # Run each profile against the directory to try to find one that matches
27
+ profile_clazz = Circus::Profiles::PROFILES.find { |p| p.accepts?(@name, @dir, @props) }
28
+ raise "No profile can run #{@dir}" unless profile_clazz
29
+
30
+ @profile = profile_clazz.new(@name, @dir, @props)
31
+ end
32
+
33
+ def package_for_dev(logger, run_root_dir)
34
+ detect! unless @profile
35
+
36
+ # Create our run directory, and tell the profile to package into it
37
+ run_dir = File.join(run_root_dir, @name)
38
+ FileUtils.mkdir_p run_dir
39
+ profile.package_for_dev(logger, run_dir)
40
+ end
41
+
42
+ def assemble(logger, output_root_dir, overlay_root)
43
+ detect! unless @profile
44
+
45
+ overlay_dir = File.join(overlay_root, name)
46
+ FileUtils.mkdir_p(overlay_dir)
47
+ return false unless profile.package_for_deploy(logger, overlay_dir)
48
+
49
+ begin
50
+ # Squash the output file
51
+ include_dirs = ["#{overlay_dir}/*"]
52
+ include_dirs << "#{@dir}/*" if profile.package_base_dir?
53
+ include_dirs.concat(profile.extra_dirs)
54
+ output_name = File.join(output_root_dir, "#{name}.act")
55
+
56
+ ExternalUtil.run_external(logger, 'Output packaging',
57
+ "mksquashfs #{include_dirs.join(' ')} #{output_name} -noappend -noI -noD -noF 2>&1")
58
+ ensure
59
+ profile.cleanup_after_deploy(logger, overlay_dir)
60
+ end
61
+ end
62
+
63
+ def upload(output_root_dir, act_store)
64
+ detect! unless @profile
65
+
66
+ output_name = File.join(output_root_dir, "#{name}.act")
67
+ act_store.upload_act(output_name)
68
+ end
69
+
70
+ def act_file
71
+ File.join(@dir, 'act.yaml')
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,30 @@
1
+ module Circus
2
+ class ActStoreClient
3
+ def initialize(root, logger)
4
+ @root = root
5
+ @logger = logger
6
+ end
7
+
8
+ def upload_act(fn)
9
+ actname = File.basename(fn)
10
+ upload_url = "#{@root}/#{actname}"
11
+
12
+ @logger.info "Uploading to #{upload_url}"
13
+ uri = URI.parse(upload_url)
14
+
15
+ res = Net::HTTP.start(uri.host, uri.port) do |http|
16
+ req = Net::HTTP::Put.new(uri.request_uri)
17
+ req.body = File.read(fn)
18
+ req.content_type = 'application/binary'
19
+
20
+ http.request req
21
+ end
22
+ unless res.is_a? Net::HTTPSuccess
23
+ @logger.error "FAILED: Act Upload"
24
+ @logger.error " Status: #{res.code}"
25
+ @logger.error " Response: #{res.body}"
26
+ return false
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,59 @@
1
+ require 'blather/client/dsl'
2
+ require 'circus/agents/params'
3
+ require 'circus/agents/logger'
4
+ require 'circus/agents/connection'
5
+
6
+ module Circus
7
+ module Agents
8
+ class Agent
9
+ include Blather::DSL
10
+
11
+ class <<self
12
+ def commands
13
+ @commands ||= []
14
+ end
15
+
16
+ def command(name, &body)
17
+ commands << name
18
+
19
+ define_method("command_#{name}", &body)
20
+ end
21
+ end
22
+
23
+ def initialize(connection = nil)
24
+ @client = (connection || Connection.new)
25
+
26
+ # Approve all subscription requests
27
+ subscription :request? do |s|
28
+ write_to_stream s.approve!
29
+ end
30
+
31
+ # Add a handler for each chat command
32
+ self.class.commands.each do |name|
33
+ message :chat?, :body => /^#{name}( .*)?$/ do |m|
34
+ # begin
35
+ params = CommandParams.new(m.body[(name.length + 1)..-1])
36
+ logger = XMPPLogger.new(m.from, m.thread || m.id, lambda { |msg| write_to_stream(msg) })
37
+
38
+ send("command_#{name}", params, logger)
39
+ # rescue
40
+ # puts $!, $@
41
+ # end
42
+ end
43
+ end
44
+
45
+ disconnected do
46
+ puts "Disconnected"
47
+ end
48
+ end
49
+
50
+ def configure!(config)
51
+ client.configure!(config)
52
+ end
53
+
54
+ def run
55
+ client.run
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,77 @@
1
+ require 'circus/agents/encoding'
2
+ require 'monitor'
3
+
4
+ module Circus
5
+ module Agents
6
+ # Client for XMPP based agents.
7
+ class Client
8
+ def initialize(connection)
9
+ @connection = connection
10
+ end
11
+
12
+ def call(to, name, params = {}, &block)
13
+ body = if params.length > 0
14
+ "#{name} #{Encoding.encode(params)}"
15
+ else
16
+ name
17
+ end
18
+ msg = Blather::Stanza::Message.new to, body
19
+ msg.id = Blather::Stanza.next_id
20
+ msg.thread = msg.id
21
+
22
+ promise = Promise.new
23
+ last = nil
24
+ @connection.register_thread_handler(msg.thread) do |m|
25
+ block.call(m)
26
+
27
+ begin
28
+ if Conversation.ended? m
29
+ result = nil
30
+ if last and last.body and last.body.start_with? 'ok '
31
+ result = Encoding.decode(last.body[('ok '.length)..-1])
32
+ end
33
+
34
+ promise.completed!(result)
35
+ else
36
+ last = m
37
+ end
38
+ rescue
39
+ puts $!, $@
40
+ end
41
+ end
42
+ @connection.write(msg)
43
+
44
+ promise
45
+ end
46
+ end
47
+
48
+ # A promise provides a reference to an expected future result. Client calls
49
+ # return immediately upon message dispatch - in order to retrieve the final
50
+ # result, the promise can be inspected.
51
+ class Promise
52
+ def initialize
53
+ @monitor = Monitor.new
54
+ @cond = @monitor.new_cond
55
+ @completed = false
56
+ @result = nil
57
+ end
58
+
59
+ def completed!(result)
60
+ @monitor.synchronize do
61
+ @completed = true
62
+ @result = result
63
+ @cond.signal
64
+ end
65
+ end
66
+
67
+ def result
68
+ @monitor.synchronize do
69
+ return @result if @completed
70
+
71
+ @cond.wait
72
+ @result
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,76 @@
1
+ require 'blather/client/client'
2
+ require 'circus/agents/conversation'
3
+ require 'monitor'
4
+
5
+ module Circus
6
+ module Agents
7
+ class Connection < Blather::Client
8
+ attr_reader :thread_handlers
9
+
10
+ def initialize
11
+ super
12
+
13
+ @ready_mon = Monitor.new
14
+ @ready_cond = @ready_mon.new_cond
15
+ @thread_handlers = {}
16
+ register_handler :message do |m|
17
+ process_chat_thread(m)
18
+ end
19
+ register_handler :disconnected do
20
+ puts "Disconnected!"
21
+ end
22
+ register_handler :ready do
23
+ @ready_mon.synchronize {
24
+ @ready_cond.signal
25
+ }
26
+ end
27
+ end
28
+
29
+ def configure!(config)
30
+ args = [config.jid, config.password]
31
+ if config.host
32
+ args << config.host
33
+ args << config.port if config.port
34
+ end
35
+
36
+ setup *args
37
+ end
38
+
39
+ def configure_bg!(config)
40
+ configure!(config)
41
+
42
+ Thread.new {
43
+ EM.run {
44
+ begin
45
+ run
46
+ rescue
47
+ puts $!, $@
48
+ end
49
+ }
50
+ }
51
+ @ready_mon.synchronize {
52
+ @ready_cond.wait(2)
53
+ }
54
+ end
55
+
56
+ def register_thread_handler(thread_id, &block)
57
+ thread_handlers[thread_id] = block
58
+ end
59
+
60
+ def remove_thread_handler(thread_id)
61
+ thread_handlers.delete(thread_id)
62
+ end
63
+
64
+ private
65
+ def process_chat_thread(m)
66
+ return false unless m.thread and thread_handlers[m.thread]
67
+
68
+ handler = thread_handlers[m.thread]
69
+ remove_thread_handler(m.thread) if Conversation.ended? m
70
+
71
+ handler.call(m)
72
+ true
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,17 @@
1
+ module Circus
2
+ module Agents
3
+ class Conversation
4
+ CHAT_STATES = 'http://jabber.org/protocol/chatstates'
5
+
6
+ def self.end(m)
7
+ gone_el = Nokogiri::XML::Element.new('gone', m.document)
8
+ gone_el.default_namespace = CHAT_STATES
9
+ m << gone_el
10
+ end
11
+
12
+ def self.ended?(m)
13
+ m.xpath('ns:gone', 'ns' => CHAT_STATES).length > 0
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,85 @@
1
+ require 'dbus'
2
+ require 'uuid'
3
+
4
+ module Circus
5
+ module Agents
6
+ class DBusConnection
7
+ def initialize(bus = nil)
8
+ @bus = bus || DBus::SystemBus.instance
9
+ end
10
+
11
+ def configure_bg!(options = {})
12
+ Thread.new do
13
+ l = DBus::Main.new
14
+ l << @bus
15
+ l.run
16
+ end
17
+ end
18
+
19
+ def call(target, object, iface, method, args, logger)
20
+ action_id = UUID.generate
21
+
22
+ @service = @bus.service("com.deployacircus.#{object}")
23
+ obj = @service.object("/com/deployacircus/#{object}")
24
+ obj.introspect
25
+ obj_iface = obj["com.deployacircus.#{iface}"]
26
+ dbus_method = obj_iface.methods[method]
27
+ raise ArgumentError.new("Method #{method} on #{object} not found") unless dbus_method
28
+
29
+ msg = DBus::Message.new(DBus::Message::METHOD_CALL)
30
+ msg.path = obj.path
31
+ msg.interface = obj_iface.name
32
+ msg.destination = obj.destination
33
+ msg.member = dbus_method.name
34
+ msg.sender = @bus.unique_name
35
+ dbus_method.params.each do |p|
36
+ if p.name == 'id'
37
+ msg.add_param p.type, action_id
38
+ else
39
+ msg.add_param(p.type, args[p.name])
40
+ end
41
+ end
42
+ promise = DBusPromise.new(@bus)
43
+ @bus.on_return(msg) do |rmsg|
44
+ promise.completed!(rmsg)
45
+ end
46
+ obj_iface.on_signal(@bus, 'LogEntry') do |log_action_id, msg|
47
+ logger.info(msg) if action_id == log_action_id
48
+ end
49
+ @bus.send(msg.marshall)
50
+
51
+ promise
52
+ end
53
+
54
+ def send_file(fn)
55
+ # Normal DBus connections can see the file locally just fine, so we don't need to
56
+ # do anything with it.
57
+ fn
58
+ end
59
+ end
60
+
61
+ class DBusPromise
62
+ def initialize(bus)
63
+ @bus = bus
64
+ @l = DBus::Main.new
65
+ @l << @bus
66
+ @result = nil
67
+ end
68
+
69
+ def result
70
+ @l.run
71
+
72
+ if @result.is_a? DBus::Error
73
+ raise @result
74
+ else
75
+ @result.params[0]
76
+ end
77
+ end
78
+
79
+ def completed!(result)
80
+ @result = result
81
+ @l.quit
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,34 @@
1
+ module Circus
2
+ module Agents
3
+ class DBusLogger
4
+ def initialize(adapter, action_id)
5
+ @adapter = adapter
6
+ @action_id = action_id
7
+ end
8
+
9
+ def info(content)
10
+ write(content)
11
+ end
12
+
13
+ def error(content)
14
+ write("ERROR: #{content}")
15
+ end
16
+
17
+ def failed(msg)
18
+ write("failed #{msg}")
19
+ end
20
+
21
+ def complete(res = nil)
22
+ if res
23
+ write("ok #{Encoding.encode(res)}")
24
+ else
25
+ write('ok')
26
+ end
27
+ end
28
+
29
+ def write(msg)
30
+ @adapter.LogEntry(@action_id, msg)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ require 'cgi'
2
+
3
+ module Circus
4
+ module Agents
5
+ class Encoding
6
+ def self.encode(params, sep = '&')
7
+ params.map do |k,v|
8
+ if v.is_a? Array
9
+ v.map do |iv|
10
+ "#{CGI.escape(k.to_s)}=#{CGI.escape(iv.to_s)}"
11
+ end.join(sep)
12
+ else
13
+ "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
14
+ end
15
+ end.join(sep)
16
+ end
17
+
18
+ def self.decode(str)
19
+ parsed = CGI::parse(str)
20
+ result = {}
21
+ parsed.each do |k, v|
22
+ if v.length == 1
23
+ result[k] = v.first
24
+ else
25
+ result[k] = v
26
+ end
27
+ end
28
+ result
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,52 @@
1
+ require 'circus/agents/encoding'
2
+ require 'circus/agents/conversation'
3
+
4
+ module Circus
5
+ module Agents
6
+ class XMPPLogger
7
+ def initialize(to, thread, writer)
8
+ @to = to
9
+ @thread = thread || "thread#{Blather::Stanza.next_id}"
10
+ @writer = writer
11
+ end
12
+
13
+ def info(content)
14
+ write("#{content}")
15
+ end
16
+
17
+
18
+ def error(content)
19
+ write("ERROR: #{content}")
20
+ end
21
+
22
+ def failed(msg)
23
+ write("failed #{msg}")
24
+ gone
25
+ end
26
+
27
+ def complete(res = nil)
28
+ if res
29
+ write("ok #{Encoding.encode(res)}")
30
+ else
31
+ write('ok')
32
+ end
33
+ gone
34
+ end
35
+
36
+ private
37
+ def write(content)
38
+ msg = Blather::Stanza::Message.new @to, content
39
+ msg.thread = @thread
40
+ @writer.call(msg)
41
+ end
42
+
43
+ def gone
44
+ msg = Blather::Stanza::Message.new @to, nil
45
+ msg.thread = @thread
46
+
47
+ Conversation.end(msg)
48
+ @writer.call(msg)
49
+ end
50
+ end
51
+ end
52
+ end