cacophony 0.0.2
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.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.rdoc +35 -0
- data/Rakefile +2 -0
- data/bin/cacophony +80 -0
- data/cacophony.gemspec +23 -0
- data/config/cacophony_sample.yaml +19 -0
- data/lib/cacophony/version.rb +3 -0
- data/lib/cacophony.rb +34 -0
- data/lib/growlnotify +0 -0
- data/lib/notifiers/email_notifier.rb +47 -0
- data/lib/notifiers/growl_notifier.rb +38 -0
- metadata +78 -0
data/Gemfile
ADDED
data/README.rdoc
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
= Cacophony notifier
|
|
2
|
+
|
|
3
|
+
* Author: David Lyons (http://loadedfingers.com)
|
|
4
|
+
|
|
5
|
+
== Caco-whatsie?
|
|
6
|
+
|
|
7
|
+
Cacophony is a small program that broadcasts notifications via a variety of mechanisms, such as growl, email and twitter.
|
|
8
|
+
It is great for notifiying you(or others) when a long running task is complete.
|
|
9
|
+
It operates as a standalone executable, and it also can read from STDIN to pipe output from your tasks to the notifiers.
|
|
10
|
+
The various notifiers are configured in ~/.cacophony, or via a config file passed via -c option.
|
|
11
|
+
|
|
12
|
+
== Requirements
|
|
13
|
+
|
|
14
|
+
* ruby 1.9.x
|
|
15
|
+
* trollop
|
|
16
|
+
* Growl (if you want growl notifications)
|
|
17
|
+
|
|
18
|
+
== Install
|
|
19
|
+
|
|
20
|
+
sudo gem install cacophony
|
|
21
|
+
|
|
22
|
+
Running cacophony for the first time will prompt you to create a sample configuration file, which you can edit as appropriate.
|
|
23
|
+
|
|
24
|
+
== Usage
|
|
25
|
+
|
|
26
|
+
Some examples:
|
|
27
|
+
|
|
28
|
+
cacophony -m 'just a message'
|
|
29
|
+
./long_task_is_long | cacophony
|
|
30
|
+
./long_task_is_long | cacophony -t 'job output:'
|
|
31
|
+
./long_task_is_long && cacophony -m 'coffee break over'
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
== Developers
|
|
35
|
+
You can add customer notifiers by adding a class to lib/notifiers/. They must follow the naming pattern xNotifier, copy one of the existing classes for method signatures.
|
data/Rakefile
ADDED
data/bin/cacophony
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require 'trollop'
|
|
5
|
+
require 'fcntl'
|
|
6
|
+
require 'fileutils'
|
|
7
|
+
|
|
8
|
+
require 'cacophony'
|
|
9
|
+
|
|
10
|
+
#resolve symlinks FIX WHEN IN GEM
|
|
11
|
+
THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
|
|
12
|
+
GEM_PATH = File.join('..','lib',File.dirname(THIS_FILE) )
|
|
13
|
+
|
|
14
|
+
RESULTS_SIZE = 50
|
|
15
|
+
DEFAULT_TITLE = 'Cacophony Notifier'
|
|
16
|
+
DEFAULT_MSG = 'Task finished!'
|
|
17
|
+
|
|
18
|
+
DEFAULT_CONF_PATH = '~/.cacophony'
|
|
19
|
+
|
|
20
|
+
opts = Trollop::options do
|
|
21
|
+
version "Cacophony v#{Cacophony::VERSION}(c) 2011 David Lyons"
|
|
22
|
+
banner <<-EOS
|
|
23
|
+
Cacophony is a small program that broadcasts notifications via a variety of mechanisms, such as growl, email and twitter.
|
|
24
|
+
It is great for notifiying you(or others) when a long running task is complete.
|
|
25
|
+
It operates as a standalone executable, and it also can read from STDIN to pipe output from your tasks to the notifiers.
|
|
26
|
+
The various notifiers are configured in #{DEFAULT_CONF_PATH}, or via a config file passed via -c option.
|
|
27
|
+
|
|
28
|
+
Usage:
|
|
29
|
+
cacophony [-options] [message]
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
./long_task_is_long | cacophony
|
|
33
|
+
./long_task_is_long | cacophony -t 'job output:'
|
|
34
|
+
./long_task_is_long && cacophony -m 'coffee break over'
|
|
35
|
+
|
|
36
|
+
Options:
|
|
37
|
+
|
|
38
|
+
EOS
|
|
39
|
+
opt :message, "The message to send via the notifiers", :short => 'm', :type => String, :default => DEFAULT_MSG
|
|
40
|
+
opt :title, "The title/subject to attach to messages", :short => 't', :type => String, :default => DEFAULT_TITLE
|
|
41
|
+
opt :conf_file, "Alternate location of config file (default: #{DEFAULT_CONF_PATH})", :short => 'c', :type => String
|
|
42
|
+
end
|
|
43
|
+
Trollop::die :conf_file, "must exist" unless File.exist?(opts[:conf_file]) if opts[:conf_file]
|
|
44
|
+
|
|
45
|
+
unless opts[:conf_file] || File.exist?(File.expand_path(DEFAULT_CONF_PATH))
|
|
46
|
+
puts "No cacophony config file found at #{DEFAULT_CONF_PATH}."
|
|
47
|
+
print "Would you like me to create a sample config file at #{DEFAULT_CONF_PATH} for you? (y/n):"
|
|
48
|
+
if $stdin.getc == 'y'
|
|
49
|
+
puts "Copying sample to #{DEFAULT_CONF_PATH}."
|
|
50
|
+
FileUtils.cp(File.join(File.dirname(THIS_FILE), '..', 'config', 'cacophony_sample.yaml'), File.expand_path(DEFAULT_CONF_PATH))
|
|
51
|
+
puts "Please edit this file to configure cacophony, and run again."
|
|
52
|
+
exit
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
CONF_FILE_PATH = opts[:conf_file] || File.join(File.expand_path('~'), '.cacophony')
|
|
58
|
+
begin
|
|
59
|
+
CONFIG = YAML.load_file(CONF_FILE_PATH)
|
|
60
|
+
rescue
|
|
61
|
+
Trollop::die "could not load config file: #{CONF_FILE_PATH}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
output = []
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
if STDIN.fcntl(Fcntl::F_GETFL, 0) == 0
|
|
68
|
+
ARGF.each do |line|
|
|
69
|
+
puts line
|
|
70
|
+
output << line
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
#output << ''
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
message = (opts[:message] == DEFAULT_MSG && m = ARGV.shift) ? m : opts[:message]
|
|
77
|
+
title = opts[:title]
|
|
78
|
+
|
|
79
|
+
notifer = Cacophony::Notifier.new(CONFIG)
|
|
80
|
+
notifer.notify(title, message, output)
|
data/cacophony.gemspec
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "cacophony/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "cacophony"
|
|
7
|
+
s.version = Cacophony::VERSION
|
|
8
|
+
s.platform = Gem::Platform::RUBY
|
|
9
|
+
s.authors = ["Dave Lyons"]
|
|
10
|
+
s.email = ["dalyons@gmail.com"]
|
|
11
|
+
s.homepage = "http://www.loadedfingers.com"
|
|
12
|
+
s.summary = %q{Broadcast messages from programs and the command line}
|
|
13
|
+
s.description = %q{see summary}
|
|
14
|
+
|
|
15
|
+
#s.rubyforge_project = "cacophony"
|
|
16
|
+
|
|
17
|
+
s.files = `git ls-files`.split("\n")
|
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
20
|
+
s.require_paths = ["lib"]
|
|
21
|
+
|
|
22
|
+
s.add_dependency('trollop')
|
|
23
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#Cacophony sample config.
|
|
2
|
+
#Each availible notifier type is listed here, along with its options.
|
|
3
|
+
#To enable a notifier, uncomment it and set the options you require.
|
|
4
|
+
|
|
5
|
+
##Growl notifer uses growl.
|
|
6
|
+
##Please ensure 'Listen for availible notifications' and 'allow remote application registration' are ticked in System Preferences->Growl.
|
|
7
|
+
#growl_notifier:
|
|
8
|
+
# use_growl_gem: false
|
|
9
|
+
# sticky: true
|
|
10
|
+
|
|
11
|
+
##Email notifier sends emails, below is a sample config for sending via gmail
|
|
12
|
+
#email_notifier:
|
|
13
|
+
# server: smtp.gmail.com
|
|
14
|
+
# port: 587
|
|
15
|
+
# tls: true
|
|
16
|
+
# username: USERNAME
|
|
17
|
+
# password: PASSWORD
|
|
18
|
+
# to_address: [addy1@gmail.com, addy2@somewhere.com]
|
|
19
|
+
# from_address: cacophony@test.com
|
data/lib/cacophony.rb
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#require all the notifiers
|
|
2
|
+
require 'cacophony/version'
|
|
3
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'notifiers', '*.rb')) {|f| require f}
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
module Cacophony
|
|
7
|
+
class Notifier
|
|
8
|
+
|
|
9
|
+
def initialize(conf)
|
|
10
|
+
raise 'need configuration hash' unless conf.is_a?(Hash) && conf.any?
|
|
11
|
+
@conf = conf
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def notify(title, message, data)
|
|
15
|
+
|
|
16
|
+
threads = []
|
|
17
|
+
@conf.each do |notifier_type, opts|
|
|
18
|
+
begin
|
|
19
|
+
klass = Object.const_get(notifier_type.split('_').map(&:capitalize).join)
|
|
20
|
+
rescue
|
|
21
|
+
raise "Invalid configuration option(s): #{notifier_type}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
threads << Thread.new do
|
|
25
|
+
notifier = klass.new(opts || {} )
|
|
26
|
+
puts "Cacophony broadcasting via #{notifier_type.split('_').map(&:capitalize).join(' ')}"
|
|
27
|
+
notifier.notify(message, title, data)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
threads.each{|t| t.join}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/growlnotify
ADDED
|
Binary file
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
require 'net/smtp'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class EmailNotifier
|
|
6
|
+
|
|
7
|
+
def initialize(opts={})
|
|
8
|
+
@opts = opts
|
|
9
|
+
@from = opts['from'] || "Your sentient shell <shell@donotfearus.com>"
|
|
10
|
+
@to = opts['to'] || "Puny human"
|
|
11
|
+
@subject = opts['subject'] || "Job Complete"
|
|
12
|
+
@server = opts['server'] || 'localhost'
|
|
13
|
+
@port = opts['port'] || 25
|
|
14
|
+
@username = opts['username'] || nil
|
|
15
|
+
@password = opts['password'] || nil
|
|
16
|
+
@method = opts['method'] || :plain
|
|
17
|
+
@to_addresses = opts['to_address'].to_a
|
|
18
|
+
@from_address = opts['from_address'] || ''
|
|
19
|
+
@tls = opts['tls'] || false
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def notify(message, title, data)
|
|
24
|
+
|
|
25
|
+
details = message.dup
|
|
26
|
+
details << "\n" + (data.any? ? "Last #{RESULTS_SIZE} lines...\n\n#{data.last(50).join}" : "No output.")
|
|
27
|
+
|
|
28
|
+
@to_addresses.each do |address|
|
|
29
|
+
|
|
30
|
+
msg = <<MESSAGE_END
|
|
31
|
+
From: #{@from}
|
|
32
|
+
To: #{@to}
|
|
33
|
+
Subject: #{title}: #{@subject}
|
|
34
|
+
|
|
35
|
+
#{details}
|
|
36
|
+
|
|
37
|
+
MESSAGE_END
|
|
38
|
+
|
|
39
|
+
smtp = Net::SMTP.new @server, @port
|
|
40
|
+
smtp.enable_starttls if @tls
|
|
41
|
+
smtp.start(@server, @username, @password, @method.to_sym) do
|
|
42
|
+
smtp.send_message(msg, @from_address, address)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'ruby-growl'
|
|
3
|
+
GROWL_GEM = true
|
|
4
|
+
rescue LoadError
|
|
5
|
+
GROWL_GEM = false
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class GrowlNotifier
|
|
9
|
+
def initialize(opts = {})
|
|
10
|
+
@server = opts['server'] || '127.0.0.1'
|
|
11
|
+
@sticky = opts['sticky'] || false
|
|
12
|
+
@use_growl_gem = opts['use_growl_gem'] == false ? false : true
|
|
13
|
+
@output_lines = opts['output_lines'] || 2
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def notify(message, title = '', data = [])
|
|
17
|
+
msg = message.dup
|
|
18
|
+
if data.any?
|
|
19
|
+
msg << "\n\n"
|
|
20
|
+
#msg << "......#{data.length - @output_lines} more lines\n"
|
|
21
|
+
#(@output_lines - 1).downto(0).each{|i| msg << "#{data.length - i}: #{data[i]}"}
|
|
22
|
+
data.last(@output_lines).each_with_index{|line,i| msg << "#{data.length - i}: #{line}"}
|
|
23
|
+
msg << "......#{data.length - @output_lines} more lines"
|
|
24
|
+
end
|
|
25
|
+
(@use_growl_gem && GROWL_GEM) ? notify_via_gem(msg, title) : notify_via_binary(msg, title)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
def notify_via_gem(message, title)
|
|
30
|
+
growl = Growl.new "127.0.0.1", "ruby-growl",["ruby-growl_Notification"]
|
|
31
|
+
growl.notify "ruby-growl_Notification", title, message
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def notify_via_binary(message, title)
|
|
35
|
+
growl_bin = File.join(GEM_PATH, 'bin', 'growlnotify')
|
|
36
|
+
system %{#{growl_bin} -m "#{msg}" "#{title}" #{"-s" if @sticky}}
|
|
37
|
+
end
|
|
38
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: cacophony
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease:
|
|
5
|
+
version: 0.0.2
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Dave Lyons
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
|
|
13
|
+
date: 2011-02-09 00:00:00 +11:00
|
|
14
|
+
default_executable:
|
|
15
|
+
dependencies:
|
|
16
|
+
- !ruby/object:Gem::Dependency
|
|
17
|
+
name: trollop
|
|
18
|
+
prerelease: false
|
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
20
|
+
none: false
|
|
21
|
+
requirements:
|
|
22
|
+
- - ">="
|
|
23
|
+
- !ruby/object:Gem::Version
|
|
24
|
+
version: "0"
|
|
25
|
+
type: :runtime
|
|
26
|
+
version_requirements: *id001
|
|
27
|
+
description: see summary
|
|
28
|
+
email:
|
|
29
|
+
- dalyons@gmail.com
|
|
30
|
+
executables:
|
|
31
|
+
- cacophony
|
|
32
|
+
extensions: []
|
|
33
|
+
|
|
34
|
+
extra_rdoc_files: []
|
|
35
|
+
|
|
36
|
+
files:
|
|
37
|
+
- .gitignore
|
|
38
|
+
- Gemfile
|
|
39
|
+
- README.rdoc
|
|
40
|
+
- Rakefile
|
|
41
|
+
- bin/cacophony
|
|
42
|
+
- cacophony.gemspec
|
|
43
|
+
- config/cacophony_sample.yaml
|
|
44
|
+
- lib/cacophony.rb
|
|
45
|
+
- lib/cacophony/version.rb
|
|
46
|
+
- lib/growlnotify
|
|
47
|
+
- lib/notifiers/email_notifier.rb
|
|
48
|
+
- lib/notifiers/growl_notifier.rb
|
|
49
|
+
has_rdoc: true
|
|
50
|
+
homepage: http://www.loadedfingers.com
|
|
51
|
+
licenses: []
|
|
52
|
+
|
|
53
|
+
post_install_message:
|
|
54
|
+
rdoc_options: []
|
|
55
|
+
|
|
56
|
+
require_paths:
|
|
57
|
+
- lib
|
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
59
|
+
none: false
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: "0"
|
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
|
+
none: false
|
|
66
|
+
requirements:
|
|
67
|
+
- - ">="
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: "0"
|
|
70
|
+
requirements: []
|
|
71
|
+
|
|
72
|
+
rubyforge_project:
|
|
73
|
+
rubygems_version: 1.5.0
|
|
74
|
+
signing_key:
|
|
75
|
+
specification_version: 3
|
|
76
|
+
summary: Broadcast messages from programs and the command line
|
|
77
|
+
test_files: []
|
|
78
|
+
|