apt_control 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/apt_control.rb CHANGED
@@ -6,10 +6,12 @@ require 'logger'
6
6
  module AptControl
7
7
 
8
8
  require 'apt_control/exec'
9
- require 'apt_control/notify'
9
+ require 'apt_control/jabber'
10
10
  require 'apt_control/control_file'
11
11
  require 'apt_control/apt_site'
12
12
  require 'apt_control/build_archive'
13
+ require 'apt_control/package_states'
14
+ require 'apt_control/includer'
13
15
 
14
16
  class Version
15
17
  include Comparable
@@ -66,9 +66,9 @@ module AptControl
66
66
  # watch the build directory, adding new packages and versions to the
67
67
  # in-memory list as it sees them. Yields to the given block with the
68
68
  # package and the new version
69
- def watch(&block)
69
+ def watch(fs_listener_factory, &block)
70
70
  @logger.info("Watching for new changes files in #{@dir}")
71
- Listen.to(@dir, :filter => /\.changes$/) do |modified, added, removed|
71
+ fs_listener_factory.new(@dir, /\.changes$/) do |modified, added, removed|
72
72
  added.each do |fname|
73
73
  begin
74
74
  fname = File.basename(fname)
@@ -89,7 +89,7 @@ module AptControl
89
89
  next
90
90
  end
91
91
  end
92
- end
92
+ end.start.join
93
93
  end
94
94
 
95
95
  class Package
@@ -39,13 +39,17 @@ module AptControl
39
39
  end
40
40
 
41
41
  module Common
42
+ # FIXME tidy up with some meta magic
43
+ def package_states ; ancestor(Root).package_states ; end
44
+ def includer ; ancestor(Root).includer ; end
42
45
  def apt_site ; ancestor(Root).apt_site ; end
43
46
  def control_file ; ancestor(Root).control_file ; end
44
47
  def build_archive ; ancestor(Root).build_archive ; end
45
- def notifier ; ancestor(Root).notify ; end
48
+ def notifier ; ancestor(Root).notifier ; end
46
49
  def notify(msg) ; ancestor(Root).notify(msg) ; end
47
50
  def validate_config! ; ancestor(Root).validate_config! ; end
48
51
  def logger ; ancestor(Root).logger ; end
52
+ def fs_listener_factory ; ancestor(Root).fs_listener_factory ; end
49
53
 
50
54
  def each_package_state(&block)
51
55
  control_file.distributions.each do |dist|
@@ -75,6 +79,7 @@ module AptControl
75
79
  config :jabber_id, "Jabber ID for notifications", :required => false
76
80
  config :jabber_password, "Password for connecting to jabber server", :required => false
77
81
  config :jabber_chatroom_id, "Jabber ID for chatroom to send notifications to", :required => false
82
+ config :disable_inotify, "Set to true to disable use of inotify", :required => false
78
83
 
79
84
  description """
80
85
  Move packages from an archive in to your reprepro style apt repository.
@@ -141,6 +146,12 @@ YAML file containing a single hash of key value/pairs for each option.
141
146
  end
142
147
  end
143
148
 
149
+ def package_states
150
+ @package_states ||= PackageStates.new(apt_site: apt_site,
151
+ build_archive: build_archive,
152
+ control_file: control_file)
153
+ end
154
+
144
155
  def apt_site
145
156
  @apt_site ||= AptSite.new(config[:apt_site_dir], logger)
146
157
  end
@@ -154,14 +165,48 @@ YAML file containing a single hash of key value/pairs for each option.
154
165
  end
155
166
 
156
167
  def notifier
157
- @notify ||= Notify::Jabber.new(:jid => config[:jabber_id], :logger => logger,
168
+ @notify ||= Jabber.new(:jid => config[:jabber_id], :logger => logger,
158
169
  :password => config[:jabber_password], :room_jid => config[:jabber_chatroom_id])
159
170
  end
160
171
 
172
+ def includer
173
+ @includer ||= Includer.new(apt_site, build_archive)
174
+ end
175
+
176
+ class FSListenerFactory
177
+
178
+ attr_reader :disable_inotify
179
+
180
+ def initialize(options={})
181
+ @disable_inotify = options[:disable_inotify]
182
+ end
183
+
184
+ def new(dir, pattern, &on_change)
185
+ Listen.to(dir).filter(pattern).tap do |listener|
186
+ if disable_inotify
187
+ listener.force_polling(true)
188
+ listener.polling_fallback_message(false)
189
+ end
190
+
191
+ listener.change(&on_change)
192
+ end
193
+ end
194
+ end
195
+
196
+ def fs_listener_factory
197
+ @fs_listener_factory ||= FSListenerFactory.new(
198
+ disable_inotify: config[:disable_inotify].to_s == 'true')
199
+ end
200
+
161
201
  def notify(message)
162
202
  logger.info("notify: #{message}")
163
- return unless config[:jabber_enabled]
164
- notifier.message(message)
203
+ return unless config[:jabber_enabled].to_s == 'true'
204
+ begin
205
+ notifier.send_message(message)
206
+ rescue => e
207
+ logger.error("Unable to send notification to jabber: #{e}")
208
+ logger.error(e)
209
+ end
165
210
  end
166
211
  end
167
212
  end
@@ -10,21 +10,12 @@ that the control file will allow"""
10
10
  def run
11
11
  validate_config!
12
12
 
13
- control_file.distributions.each do |dist|
14
- dist.package_rules.each do |rule|
15
- included = apt_site.included_version(dist.name, rule.package_name)
16
- available = build_archive[rule.package_name]
17
-
18
- next unless available
19
-
20
- if rule.upgradeable?(included, available)
21
- version = rule.upgradeable_to(available).max
22
- if options[:noop]
23
- puts "I want to upgrade from #{included} to version #{version} of #{rule.package_name}"
24
- else
25
- apt_site.include!(dist.name, build_archive.changes_fname(rule.package_name, version))
26
- end
27
- end
13
+ includer.perform_for_all(package_states) do |state, version|
14
+ if options[:noop]
15
+ puts "#{state.dist.name} #{state.package_name} #{state.included} => #{version}"
16
+ false
17
+ else
18
+ true
28
19
  end
29
20
  end
30
21
  end
@@ -9,33 +9,29 @@ module AptControl::CLI
9
9
  def run
10
10
  validate_config!
11
11
 
12
- control_file.distributions.each do |dist|
13
- puts dist.name unless options[:machine_readable]
14
- dist.package_rules.each do |rule|
15
- included = apt_site.included_version(dist.name, rule.package_name)
16
- available = build_archive[rule.package_name]
17
-
18
- satisfied = included && rule.satisfied_by?(included)
19
- upgradeable = available && rule.upgradeable?(included, available)
20
-
21
- if options[:machine_readable]
22
- fields = [
23
- dist.name,
24
- rule.package_name,
25
- "(#{rule.restriction} #{rule.version})",
26
- "#{upgradeable ? 'U' : '.'}#{satisfied ? 'S' : '.'}",
27
- "included=#{included || '<none>'}",
28
- "available=#{available && available.join(', ') || '<none>'} "
29
- ]
30
- puts fields.join(' ')
31
- else
32
- puts " #{rule.package_name}"
33
- puts " rule - #{rule.restriction} #{rule.version}"
34
- puts " included - #{included}"
35
- puts " available - #{available && available.join(', ')}"
36
- puts " satisfied - #{satisfied}"
37
- puts " upgradeable - #{upgradeable}"
38
- end
12
+ if options[:machine_readable]
13
+ package_states.each do |state|
14
+ fields = [
15
+ state.dist.name,
16
+ state.package_name,
17
+ "(#{state.rule.restriction} #{state.rule.version})",
18
+ "#{state.includeable? ? 'I' : '.'}#{state.satisfied? ? 'S' : '.'}",
19
+ "included=#{state.included || '<none>'}",
20
+ "available=#{state.available? ? state.available.join(', ') : '<none>'} "
21
+ ]
22
+ puts fields.join(' ')
23
+ end
24
+ else
25
+ last_dist = nil
26
+ package_states.each do |state|
27
+ puts state.dist.name if last_dist != state.dist
28
+ last_dist = state.dist
29
+ puts " #{state.package_name}"
30
+ puts " rule - #{state.rule.restriction} #{state.rule.version}"
31
+ puts " included - #{state.included}"
32
+ puts " available - #{state.available.join(', ')}"
33
+ puts " satisfied - #{state.satisfied?}"
34
+ puts " includeable - #{state.includeable?}"
39
35
  end
40
36
  end
41
37
  end
@@ -55,40 +55,69 @@ has the usual set of options for running as an init.d style daemon.
55
55
  end
56
56
 
57
57
  def start_watching
58
+ threads = [
59
+ watch_control_in_new_thread,
60
+ watch_build_archive_in_new_thread
61
+ ]
62
+
63
+ notify("apt_control watcher is up, waiting for changes to control file and new packages...")
64
+
65
+ # these should never exit, so stop main thread exiting by joining to them
66
+ threads.each(&:join)
67
+ end
68
+
69
+ def watch_control_in_new_thread
58
70
  # update the all the rules if the control file changes
59
- Thread.new { control_file.watch { notify "Control file reloaded" } }
60
-
61
- notify("Watching for new packages in #{build_archive.dir}")
62
- build_archive.watch do |package, new_version|
63
- notify("new package: #{package.name} at #{new_version}")
64
-
65
- updated = control_file.distributions.map do |dist|
66
- rule = dist[package.name] or next
67
- included = apt_site.included_version(dist.name, package.name)
68
-
69
- if rule.upgradeable?(included, [new_version])
70
- if options[:noop]
71
- notify("package #{package.name} can be upgraded to #{new_version} on #{dist.name} (noop)")
72
- else
73
- # FIXME error handling here, please
74
- begin
75
- apt_site.include!(dist.name, build_archive.changes_fname(rule.package_name, new_version))
76
- notify("included package #{package.name}-#{new_version} in #{dist.name}")
77
- rescue => e
78
- notify("Failed to include package #{package.name}-#{new_version}, check log for more details")
79
- logger.error("failed to include package #{package.name}")
80
- logger.error(e)
81
- end
71
+ Thread.new do
72
+ begin
73
+ control_file.watch(fs_listener_factory) do
74
+ notify "Control file reloaded"
75
+ # FIXME need to do some kind of locking or actor style dev for this
76
+ # as it looks like there could be some concurrency bugs lurking
77
+ includer.perform_for_all(package_states) do |package_state, new_version|
78
+ notify("included package #{package_state.package_name}-#{new_version} in #{package_state.dist.name}")
79
+ true
82
80
  end
83
- dist.name
84
- else
85
- nil
86
81
  end
87
- end.compact
82
+ ensure
83
+ logger.warn("control file watch loop exited")
84
+ end
85
+ end
86
+ end
87
+
88
+ def watch_build_archive_in_new_thread
89
+ Thread.new do
90
+ begin
91
+ build_archive.watch(fs_listener_factory) do |package, new_version|
92
+ handle_new_package(package, new_version)
93
+ end
94
+ ensure
95
+ logger.warn("build archive watch loop exited")
96
+ end
97
+ end
98
+ end
88
99
 
89
- if updated.size == 0
90
- notify("package #{package.name} could not be updated on any distributions")
100
+ def handle_new_package(package, new_version)
101
+ notify("new package: #{package.name} at #{new_version}")
102
+
103
+ matched_states = package_states.select {|s| s.package_name == package.name }
104
+
105
+ updated = matched_states.map do |state|
106
+ if state.includeable_to.max == new_version
107
+ begin
108
+ includer.perform_for(state, new_version, options[:noop])
109
+ notify("included package #{package.name}-#{new_version} in #{state.dist.name}")
110
+ state.dist.name
111
+ rescue => e
112
+ notify("Failed to include package #{package.name}-#{new_version}, check log for more details")
113
+ logger.error("failed to include package #{package.name}")
114
+ logger.error(e)
115
+ end
91
116
  end
117
+ end.compact
118
+
119
+ if updated.size == 0
120
+ notify("package #{package.name} could not be updated on any distributions")
92
121
  end
93
122
  end
94
123
  end
@@ -40,12 +40,12 @@ module AptControl
40
40
 
41
41
  # Watch the control file for changes, rebuilding
42
42
  # internal data structures when it does
43
- def watch(&block)
43
+ def watch(fs_listener_factory, &block)
44
44
  path = File.expand_path(@path)
45
- @logger.info("Watching for changes to #{path}")
46
45
  dir = File.dirname(path)
47
46
  fname = File.basename(path)
48
- Listen.to(dir, :filter => /#{Regexp.quote(fname)}/) do |modified, added, removed|
47
+ @logger.info("Watching for changes to #{path}")
48
+ fs_listener_factory.new(dir, /#{Regexp.quote(fname)}/) do |modified, added, removed|
49
49
  begin
50
50
  @logger.info("Change to control file detected...")
51
51
  inifile = IniFile.load(path)
@@ -60,7 +60,7 @@ module AptControl
60
60
  @logger.error("Error reloading changes: #{e}")
61
61
  @logger.error(e)
62
62
  end
63
- end
63
+ end.start.join
64
64
  end
65
65
 
66
66
  class PackageRule
@@ -111,14 +111,14 @@ module AptControl
111
111
 
112
112
  # will return true if a) there is a higher version available than is
113
113
  # included b) any of the available packages satisfy this rule
114
- def upgradeable?(included, available)
114
+ def includeable?(included, available)
115
115
  return false unless higher_available?(included, available)
116
116
  higher = available.select {|a| a > included }
117
117
  return true if higher.any? {|a| satisfied_by?(a) }
118
118
  end
119
119
 
120
120
  # will return the subset of versions from available that satisfy this rule
121
- def upgradeable_to(available)
121
+ def includeable_to(available)
122
122
  available.select {|a| satisfied_by?(a) }
123
123
  end
124
124
  end
@@ -0,0 +1,27 @@
1
+ module AptControl
2
+
3
+ # Wraps the common functionality involved in including the latest includeable
4
+ # package in an apt site
5
+ class Includer
6
+ def initialize(apt_site, build_archive)
7
+ @apt_site = apt_site
8
+ @build_archive = build_archive
9
+ end
10
+
11
+ def perform_for_all(package_states, &visitor)
12
+ package_states.each do |state|
13
+ next unless state.includeable?
14
+
15
+ version = state.includeable_to.max
16
+ perform = (block_given? && yield(state, version)) || true
17
+
18
+ perform_for(state, version) if perform
19
+ end
20
+ end
21
+
22
+ def perform_for(state, version, noop=false)
23
+ changes_fname = @build_archive.changes_fname(state.package_name, version)
24
+ @apt_site.include!(state.dist.name, changes_fname) unless noop
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,117 @@
1
+ require 'xmpp4r/jid'
2
+ require 'xmpp4r/client'
3
+ require 'xmpp4r/muc'
4
+ require 'xmpp4r/muc/helper/simplemucclient'
5
+
6
+ module AptControl
7
+ class Jabber
8
+ include ::Jabber
9
+
10
+ def initialize(options)
11
+ @jid = options[:jid]
12
+ @password = options[:password]
13
+ @room_jid = options[:room_jid]
14
+ @logger = options[:logger]
15
+
16
+ swallow_errors { connect! } unless options[:defer_connect]
17
+ end
18
+
19
+ def send_message(msg)
20
+ if not_connected?
21
+ connect!
22
+ end
23
+
24
+ begin
25
+ attempt_reconnect do
26
+ @logger.info("sending message to chat room: #{msg}")
27
+ @muc.send(Message.new(nil, msg))
28
+ end
29
+ rescue JabberError => e
30
+ raise SendError.new("failed to send message to chat room", e)
31
+ end
32
+ end
33
+
34
+ # execute the block, swallow any Jabber::Error errors it raises, reporting
35
+ # them to the logger
36
+ def swallow_errors(jabber_errors_too=false, &block)
37
+ begin
38
+ yield(self)
39
+ rescue Error => e
40
+ @logger.error("swallowed error: #{e}")
41
+ @logger.error(e)
42
+ rescue JabberError => e
43
+ raise unless jabber_errors_too
44
+ @logger.error("swallowed error: #{e}")
45
+ @logger.error(e)
46
+ end
47
+ end
48
+
49
+ def connected?
50
+ @client && @client.is_connected? && @muc && @muc.active?
51
+ end
52
+
53
+ def not_connected? ; ! connected? ; end
54
+
55
+ private
56
+
57
+ def attempt_reconnect(&block)
58
+ begin
59
+ yield
60
+ rescue JabberError => e
61
+ @logger.error("swallowing jabber error: #{e}")
62
+ @logger.error(e)
63
+ @logger.error("attempting message send again...")
64
+ connect!
65
+ yield
66
+ end
67
+ end
68
+
69
+ def connect!
70
+ # ::Jabber::debug = true
71
+ begin
72
+ swallow_errors { @client.disconnect if @client && @client.is_connected? }
73
+
74
+ @logger.info("Jabber connecting with jid #{@jid}")
75
+ @client = Client.new(JID.new(@jid))
76
+ @client.connect
77
+ @client.auth(@password)
78
+ rescue JabberError => e
79
+ raise ConnectionError.new("error connecting to client", e)
80
+ end
81
+
82
+ begin
83
+ swallow_errors { @muc.exit("reconnecting") if @muc && @muc.active? }
84
+
85
+ @muc = Jabber::MUC::SimpleMUCClient.new(@client)
86
+ @muc.join(JID.new(@room_jid))
87
+ @logger.info("joined room #{@room_jid}")
88
+ rescue JabberError => e
89
+ raise ConnectionError.new("error joining room", e)
90
+ end
91
+ end
92
+
93
+ # Thank you to http://rubyforge.org/projects/nestegg for the pattern
94
+ class Error < StandardError
95
+
96
+ attr_reader :cause
97
+ alias :wrapped_error :cause
98
+
99
+ def initialize(msg, cause=nil)
100
+ @cause = cause
101
+ super(msg)
102
+ end
103
+
104
+ def set_backtrace(bt)
105
+ if cause
106
+ bt << "cause: #{cause.class.name}: #{cause}"
107
+ bt.concat cause.backtrace
108
+ end
109
+ super(bt)
110
+ end
111
+
112
+ end
113
+
114
+ class ConnectionError < Error ; end
115
+ class SendError < Error ; end
116
+ end
117
+ end
@@ -0,0 +1,59 @@
1
+ module AptControl
2
+ class PackageStates
3
+ include Enumerable
4
+
5
+ def initialize(options)
6
+ @apt_site = options.fetch(:apt_site)
7
+ @build_archive = options.fetch(:build_archive)
8
+ @control_file = options.fetch(:control_file)
9
+ end
10
+
11
+ # yield a package state for each entry in the control file
12
+ def each(&block)
13
+ @control_file.distributions.each do |dist|
14
+ dist.package_rules.each do |rule|
15
+ yield PackageState.new(dist: dist, rule: rule, apt_site: @apt_site,
16
+ build_archive: @build_archive)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ # Brings together the state of a particular package in a particular
23
+ # distribution
24
+ class PackageState
25
+
26
+ attr_reader :dist, :rule
27
+
28
+ def initialize(options)
29
+ @dist = options.fetch(:dist)
30
+ @rule = options.fetch(:rule)
31
+ @apt_site = options.fetch(:apt_site)
32
+ @build_archive = options.fetch(:build_archive)
33
+ end
34
+
35
+ def included
36
+ @included ||= @apt_site.included_version(dist.name, rule.package_name)
37
+ end
38
+
39
+ def available
40
+ @available ||= (@build_archive[rule.package_name] || [])
41
+ end
42
+
43
+ def package_name ; rule.package_name ; end
44
+ def included? ; !! included ; end
45
+ def available? ; available.any? ; end
46
+
47
+ def satisfied?
48
+ included? && rule.satisfied_by?(included)
49
+ end
50
+
51
+ def includeable?
52
+ available? && rule.includeable?(included, available)
53
+ end
54
+
55
+ def includeable_to
56
+ rule.includeable_to(available)
57
+ end
58
+ end
59
+ end
@@ -1,3 +1,3 @@
1
1
  module AptControl
2
- VERSION = '0.3.2'
2
+ VERSION = '0.4.0'
3
3
  end
metadata CHANGED
@@ -1,151 +1,159 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: apt_control
3
- version: !ruby/object:Gem::Version
4
- hash: 23
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 3
9
- - 2
10
- version: 0.3.2
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Nick Griffiths
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2013-05-27 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2013-06-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: popen4
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 3
29
- segments:
30
- - 0
31
- version: "0"
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
32
22
  type: :runtime
33
- version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
35
- name: climate
36
23
  prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
- none: false
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- hash: 3
43
- segments:
44
- - 0
45
- version: "0"
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: climate
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
46
38
  type: :runtime
47
- version_requirements: *id002
48
- - !ruby/object:Gem::Dependency
49
- name: inifile
50
39
  prerelease: false
51
- requirement: &id003 !ruby/object:Gem::Requirement
52
- none: false
53
- requirements:
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- hash: 3
57
- segments:
58
- - 0
59
- version: "0"
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: inifile
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
60
54
  type: :runtime
61
- version_requirements: *id003
62
- - !ruby/object:Gem::Dependency
63
- name: xmpp4r
64
55
  prerelease: false
65
- requirement: &id004 !ruby/object:Gem::Requirement
66
- none: false
67
- requirements:
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- hash: 3
71
- segments:
72
- - 0
73
- version: "0"
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: xmpp4r
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
74
70
  type: :runtime
75
- version_requirements: *id004
76
- - !ruby/object:Gem::Dependency
77
- name: listen
78
71
  prerelease: false
79
- requirement: &id005 !ruby/object:Gem::Requirement
72
+ version_requirements: !ruby/object:Gem::Requirement
80
73
  none: false
81
- requirements:
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: listen
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
82
83
  - - ~>
83
- - !ruby/object:Gem::Version
84
- hash: 5
85
- segments:
86
- - 0
87
- - 7
88
- version: "0.7"
84
+ - !ruby/object:Gem::Version
85
+ version: '1.1'
89
86
  type: :runtime
90
- version_requirements: *id005
91
- - !ruby/object:Gem::Dependency
92
- name: rb-inotify
93
87
  prerelease: false
94
- requirement: &id006 !ruby/object:Gem::Requirement
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '1.1'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rb-inotify
96
+ requirement: !ruby/object:Gem::Requirement
95
97
  none: false
96
- requirements:
98
+ requirements:
97
99
  - - ~>
98
- - !ruby/object:Gem::Version
99
- hash: 25
100
- segments:
101
- - 0
102
- - 9
103
- version: "0.9"
100
+ - !ruby/object:Gem::Version
101
+ version: '0.9'
104
102
  type: :runtime
105
- version_requirements: *id006
106
- - !ruby/object:Gem::Dependency
107
- name: rspec
108
103
  prerelease: false
109
- requirement: &id007 !ruby/object:Gem::Requirement
110
- none: false
111
- requirements:
112
- - - ">="
113
- - !ruby/object:Gem::Version
114
- hash: 3
115
- segments:
116
- - 0
117
- version: "0"
118
- type: :development
119
- version_requirements: *id007
120
- - !ruby/object:Gem::Dependency
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: '0.9'
110
+ - !ruby/object:Gem::Dependency
121
111
  name: minitest
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
122
119
  prerelease: false
123
- requirement: &id008 !ruby/object:Gem::Requirement
124
- none: false
125
- requirements:
126
- - - ">="
127
- - !ruby/object:Gem::Version
128
- hash: 3
129
- segments:
130
- - 0
131
- version: "0"
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: mocha
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
132
134
  type: :development
133
- version_requirements: *id008
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
134
142
  description:
135
- email:
143
+ email:
136
144
  - nicobrevin@gmail.com
137
- executables:
145
+ executables:
138
146
  - apt_control
139
147
  extensions: []
140
-
141
148
  extra_rdoc_files: []
142
-
143
- files:
149
+ files:
144
150
  - bin/apt_control
145
151
  - lib/apt_control.rb
152
+ - lib/apt_control/jabber.rb
153
+ - lib/apt_control/package_states.rb
146
154
  - lib/apt_control/cli.rb
147
- - lib/apt_control/notify.rb
148
155
  - lib/apt_control/version.rb
156
+ - lib/apt_control/includer.rb
149
157
  - lib/apt_control/exec.rb
150
158
  - lib/apt_control/cli/watch.rb
151
159
  - lib/apt_control/cli/include.rb
@@ -155,38 +163,26 @@ files:
155
163
  - lib/apt_control/control_file.rb
156
164
  homepage: http://github.com/playlouder/apt_control
157
165
  licenses: []
158
-
159
166
  post_install_message:
160
167
  rdoc_options: []
161
-
162
- require_paths:
168
+ require_paths:
163
169
  - lib
164
- required_ruby_version: !ruby/object:Gem::Requirement
170
+ required_ruby_version: !ruby/object:Gem::Requirement
165
171
  none: false
166
- requirements:
167
- - - ">="
168
- - !ruby/object:Gem::Version
169
- hash: 3
170
- segments:
171
- - 0
172
- version: "0"
173
- required_rubygems_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ! '>='
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ required_rubygems_version: !ruby/object:Gem::Requirement
174
177
  none: false
175
- requirements:
176
- - - ">="
177
- - !ruby/object:Gem::Version
178
- hash: 23
179
- segments:
180
- - 1
181
- - 3
182
- - 6
178
+ requirements:
179
+ - - ! '>='
180
+ - !ruby/object:Gem::Version
183
181
  version: 1.3.6
184
182
  requirements: []
185
-
186
183
  rubyforge_project:
187
184
  rubygems_version: 1.8.24
188
185
  signing_key:
189
186
  specification_version: 3
190
187
  summary: Automatically manage an apt repository that changes a lot
191
188
  test_files: []
192
-
@@ -1,37 +0,0 @@
1
- require 'stringio'
2
- require 'xmpp4r/jid'
3
- require 'xmpp4r/client'
4
- require 'xmpp4r/muc'
5
- require 'xmpp4r/muc/helper/simplemucclient'
6
-
7
- module AptControl::Notify
8
-
9
- class Jabber
10
- include ::Jabber
11
-
12
- def initialize(options={})
13
- @jid = options[:jid]
14
- @password = options[:password]
15
- @room_jid = options[:room_jid]
16
- @logger = options[:logger]
17
-
18
- connect!
19
- end
20
-
21
- def connect!
22
- # ::Jabber::debug = true
23
- @logger.info("Jabber connecting with jid #{@jid}")
24
- @client = Client.new(JID.new(@jid))
25
- @client.connect
26
- @client.auth(@password)
27
-
28
- @muc = Jabber::MUC::SimpleMUCClient.new(@client)
29
- @muc.join(JID.new(@room_jid))
30
- @logger.info("joined room #{@room_jid}")
31
- end
32
-
33
- def message(msg)
34
- @muc.send(Message.new(nil, msg))
35
- end
36
- end
37
- end