circus-deployment 0.0.1

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.
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