blertr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,11 @@
1
+ require 'autotest/fsevent'
2
+ require 'autotest/growl'
3
+
4
+ Autotest.add_hook :initialize do |at|
5
+ at.clear_mappings
6
+ at.add_exception(/\.git/)
7
+ at.add_exception(/spec\/sandbox/)
8
+ at.add_mapping(%r{^spec/.*_spec}) {|filename,_| at.files_matching %r{#{filename}}}
9
+ at.add_mapping(%r{}) {|_,_| at.files_matching %r{spec/.*_spec}}
10
+ end
11
+
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .bundle/*
2
+ update/*
3
+ coverage/*
4
+ *.swp
5
+ spec/sandbox/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ blertr (0.1.0)
5
+ twitter (~> 1.6.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ addressable (2.2.6)
11
+ diff-lcs (1.1.2)
12
+ faraday (0.6.1)
13
+ addressable (~> 2.2.4)
14
+ multipart-post (~> 1.1.0)
15
+ rack (>= 1.1.0, < 2)
16
+ faraday_middleware (0.6.5)
17
+ faraday (~> 0.6.0)
18
+ hashie (1.0.0)
19
+ multi_json (1.0.3)
20
+ multi_xml (0.2.2)
21
+ multipart-post (1.1.2)
22
+ rack (1.3.0)
23
+ rdoc (2.5.11)
24
+ rspec (2.6.0)
25
+ rspec-core (~> 2.6.0)
26
+ rspec-expectations (~> 2.6.0)
27
+ rspec-mocks (~> 2.6.0)
28
+ rspec-core (2.6.4)
29
+ rspec-expectations (2.6.0)
30
+ diff-lcs (~> 1.1.2)
31
+ rspec-mocks (2.6.0)
32
+ simple_oauth (0.1.5)
33
+ simplecov (0.4.2)
34
+ simplecov-html (~> 0.4.4)
35
+ simplecov-html (0.4.5)
36
+ twitter (1.6.0)
37
+ faraday (~> 0.6.1)
38
+ faraday_middleware (~> 0.6.3)
39
+ hashie (~> 1.0.0)
40
+ multi_json (~> 1.0.0)
41
+ multi_xml (~> 0.2.0)
42
+ simple_oauth (~> 0.1.5)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ blertr!
49
+ bundler (~> 1.0)
50
+ rdoc (~> 2.5)
51
+ rspec (~> 2.3)
52
+ simplecov (~> 0.4)
data/LICENSE.textile ADDED
File without changes
data/README.textile ADDED
File without changes
data/bin/blert ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Run the command, including arguments with spaces
4
+ "$@"
5
+ status=$?
6
+
7
+ # decide which status to use
8
+ if [ "$status" == "0" ] ; then
9
+ result="completed"
10
+ else
11
+ result="FAILED ($status)"
12
+ fi
13
+
14
+ # decide which notifier we have
15
+ env growlnotify -h > /dev/null 2> /dev/null
16
+ has_growl=$?
17
+ env notify-send > /dev/null 2> /dev/null
18
+ has_libnotify=$?
19
+
20
+ # notify the user, growl or libnotify
21
+ if [ "$has_growl" == "0" ] ; then
22
+ growlnotify -m "Script '$@' $result" -n "Blert Notification"
23
+ elif [ "$has_libnotify" == "0" ] ; then
24
+ notify-send "Script '$@' $result" "Blert Notification" &
25
+ fi
26
+
27
+ # exit with the original status
28
+ exit $status
29
+
data/bin/blert_now ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby -W0
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
4
+
5
+ require 'blertr'
6
+
7
+ # interface between shell and ruby code
8
+ # not meant to be called directly by user
9
+ #
10
+ # input from shell is the command name that ran
11
+ # and how many seconds it ran for
12
+
13
+ command_name = ARGV[0]
14
+ command_seconds = ARGV[1].to_i
15
+ if command_name and command_seconds
16
+ Blertr::Control::alert command_name, command_seconds
17
+ else
18
+ puts "usage: blertr_now command time_taken"
19
+ end
20
+
data/bin/blertr ADDED
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
4
+
5
+ require 'blertr'
6
+
7
+ action = ARGV.shift
8
+ parameters = ARGV
9
+
10
+ def add_services services, time
11
+ puts services
12
+ end
13
+
14
+ def help
15
+ help_string = <<EOS
16
+ -=[ Welcome to Blertr - Notifications for Bash commands ]=-
17
+
18
+ Usage: blertr [command] [command parameters]
19
+
20
+ Commands:
21
+ help Output this help message
22
+
23
+ install Add symlinks to your system to allow
24
+ Blertr to function properly
25
+
26
+ uninstall Remove symlinks and other setup process
27
+ Effectively uninstalling Blertr
28
+
29
+ info Pass in a notifier name to get the
30
+ information it is using to send notifications
31
+ Example: blertr info email
32
+
33
+ exclude Pass in a shell command to prevent Blertr from
34
+ sending notifications when that command is
35
+ executed
36
+ Example: blertr exclude ssh
37
+
38
+ time Pass in a notifier name and a time string to
39
+ set the time required to pass before the
40
+ notifier sends a message for a command
41
+ Example: blertr time email 5 minutes
42
+ This would make blertr send an email only if
43
+ the command executing took longer than 5 mins
44
+ EOS
45
+ puts help_string
46
+ end
47
+
48
+ def take_action action, parameters
49
+ case action
50
+ when "help"
51
+ help
52
+ when "install"
53
+ blertr_path = File.expand_path(File.join(File.dirname(__FILE__), ".."))
54
+ blertr_symlink = File.expand_path("~/.blertr")
55
+ if File.exists? blertr_symlink
56
+ puts "ERROR: Blertr appears to already be installed.\nUninstall with blertr remove"
57
+ else
58
+ puts "creating symlink from #{blertr_path} to #{blertr_symlink}"
59
+ system("ln -s #{blertr_path} #{blertr_symlink}")
60
+ puts "Blertr is now (almost) installed!\nPut this at the bottom of your .bashrc file:"
61
+ puts "[[ -s \"$HOME/.blertr/scripts/blertr\" ]] && . \"$HOME/.blertr/scripts/blertr\""
62
+ end
63
+ when "uninstall"
64
+ blertr_symlink = File.expand_path("~/.blertr")
65
+ if File.exists? blertr_symlink
66
+ puts "Removing ~/.blertr"
67
+ system("rm #{blertr_symlink}")
68
+ puts "Blertr is now (almost) uninstalled.\nRemove from .bashrc file:"
69
+ puts "[[ -s \"$HOME/.blertr/scripts/blertr\" ]] && . \"$HOME/.blertr/scripts/blertr\""
70
+ else
71
+ puts "ERROR: it doesn't look like Blertr is installed"
72
+ end
73
+ when "info"
74
+ puts "getting info"
75
+ when "status"
76
+ puts "getting status"
77
+ when "exclude"
78
+ name = parameters.join(" ")
79
+ puts "Excluding #{name} from Blertr alerts"
80
+ Blertr::Blacklist.new.add(name)
81
+ when "time"
82
+ notifier_found = false
83
+ notifiers = parameters.shift.split(",")
84
+ notifiers.each do |notifier|
85
+ if Blertr::Control::is_notifier? notifier
86
+ notifier_found = true
87
+ new_time = parameters.join(" ")
88
+ Blertr::Control::change_time notifier, new_time
89
+ end
90
+ end
91
+
92
+ if !notifier_found
93
+ puts "Sorry, #{action} isn't a notifier."
94
+ puts "Use blertr status for a list of all notifiers"
95
+ end
96
+ else
97
+ puts "Sorry, #{action} isn't a recognized command"
98
+ puts "use blertr help to get a list of availible commands."
99
+ end
100
+ end
101
+
102
+ if action
103
+ take_action action.downcase, parameters
104
+ else
105
+ puts "usage blertr [command] [command parameters]"
106
+ end
data/blertr.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/blertr/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.add_development_dependency "bundler", "~> 1.0"
6
+ s.add_development_dependency "rdoc", "~> 2.5"
7
+ s.add_development_dependency "rspec", "~> 2.3"
8
+ s.add_development_dependency "simplecov", "~> 0.4"
9
+ s.add_dependency "twitter", "~> 1.6.0"
10
+ s.authors = ['Jim Vallandingham']
11
+ s.description = %q{Bash Alerts: alerts for when bash scripts and commands complete}
12
+ s.email = 'vvv@gmail.com'
13
+ s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
14
+ s.extra_rdoc_files = ['LICENSE.textile', 'README.textile']
15
+ s.files = `git ls-files`.split("\n")
16
+ s.homepage = 'http://github.com/vlandham/blertr'
17
+ s.name = 'blertr'
18
+ s.rdoc_options = ['--charset=UTF-8']
19
+ s.require_paths = ['lib']
20
+ s.required_rubygems_version = Gem::Requirement.new('>= 1.3.6')
21
+ s.summary = s.description
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.version = Blertr::VERSION.dup
24
+ end
25
+
@@ -0,0 +1,6 @@
1
+ ---
2
+ - autotest
3
+ - ssh
4
+ - git diff
5
+ - irb
6
+ - man
@@ -0,0 +1 @@
1
+ time: 6
@@ -0,0 +1,5 @@
1
+ ---
2
+ :username: blertr.app
3
+ :password: The.blert$
4
+ :to: vlandham@gmail.com
5
+ :time: 300
@@ -0,0 +1,58 @@
1
+ require 'fileutils'
2
+
3
+ module Blertr
4
+ class Blacklist
5
+ attr_accessor :path, :list
6
+
7
+ def self.path
8
+ File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "config", "blacklist.yaml"))
9
+ end
10
+
11
+ def initialize path = Blacklist::path
12
+ @path = path
13
+ @list = []
14
+ if !File.exists?(@path)
15
+ create
16
+ end
17
+ yaml_data = YAML::load(open(@path))
18
+ @list = yaml_data.to_a if yaml_data
19
+ end
20
+
21
+ def add name
22
+ @list << conform(name)
23
+ save @list
24
+ end
25
+
26
+ def conform name
27
+ name.downcase.strip
28
+ end
29
+
30
+ def blacklisted? command
31
+ rtn = false
32
+ @list.each do |name|
33
+ if command =~ /^#{name}/
34
+ rtn = true
35
+ return rtn
36
+ end
37
+ end
38
+ rtn
39
+ end
40
+
41
+ def clear
42
+ if File.exists? @path
43
+ FileUtils.rm(@path)
44
+ end
45
+ end
46
+
47
+ def save new_list
48
+ File.open(@path, 'w') do |file|
49
+ file.puts(YAML::dump(new_list))
50
+ end
51
+ end
52
+
53
+ def create
54
+ system("touch #{@path}")
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,68 @@
1
+ require 'blertr/message'
2
+ require 'blertr/mail_notifier'
3
+ require 'blertr/growl_notifier'
4
+ require 'blertr/twitter_notifier'
5
+ require 'blertr/time_parser'
6
+ require 'blertr/blacklist.rb'
7
+
8
+ module Blertr
9
+ class Control
10
+ # Sends out alert from each notifier if
11
+ # time passed is long enough
12
+ def self.alert command_name, command_time
13
+ blacklist = Blacklist.new
14
+ if !blacklist.blacklisted?(command_name)
15
+ message = Message.new(command_name, command_time)
16
+ notifiers.each do |notifier|
17
+ if notifier.will_alert?(message.command, message.seconds)
18
+ fork do
19
+ begin
20
+ notifier.alert message
21
+ rescue
22
+ puts "problem with #{notifier.name} alert"
23
+ end
24
+ exit
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def self.notifiers
32
+ noters = []
33
+ noters << MailNotifier.new
34
+ noters << GrowlNotifier.new
35
+ noters << TwitterNotifier.new
36
+ noters
37
+ end
38
+
39
+ def self.notifier_with_name name
40
+ notifiers.each do |notifier|
41
+ if name == notifier.name
42
+ return notifier
43
+ end
44
+ if notifier.names.include? name
45
+ return notifier
46
+ end
47
+ end
48
+ nil
49
+ end
50
+
51
+ def self.is_notifier? name
52
+ notifier_with_name(name) != nil
53
+ end
54
+
55
+ def self.change_time name, time_string
56
+ time_seconds = TimeParser::to_seconds time_string
57
+ if time_seconds.nil?
58
+ puts "ERROR: not valid time: #{time_string}"
59
+ else
60
+ notifier = notifier_with_name name
61
+ if notifier
62
+ puts "setting #{name} to alert after #{time_seconds} seconds"
63
+ notifier.set_time time_seconds
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,20 @@
1
+ require 'blertr/notifier'
2
+
3
+ module Blertr
4
+ class GrowlNotifier < Notifier
5
+ def initialize
6
+ super
7
+ @names = ["growl"]
8
+ end
9
+
10
+ def alert message
11
+ #TODO: look to supporting other growl frameworks on other OSs
12
+ system("growlnotify -n \"Terminal\" -m \"took #{message.time_string}\" \"#{message.command}\"")
13
+ end
14
+
15
+ def can_alert?
16
+ results = %x[which growlnotify]
17
+ !results.nil? and !results.empty?
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,37 @@
1
+ require 'blertr/notifier'
2
+ require 'net/smtp'
3
+
4
+ module Blertr
5
+ class MailNotifier < Notifier
6
+ def initialize
7
+ super
8
+ @names = ["mail", "email"]
9
+ end
10
+
11
+ def alert message
12
+ username = options[:username]
13
+ password = options[:password]
14
+ receiver = options[:to]
15
+ msg = create_message(message)
16
+ smtp = Net::SMTP.new 'smtp.gmail.com', 587
17
+ smtp.enable_starttls
18
+ smtp.start('gmail.com', username, password, :login) do
19
+ smtp.send_message(msg, "#{username}@gmail.com", receiver)
20
+ end
21
+ end
22
+
23
+ def create_message message
24
+ msg = "Subject: #{message.command_short_name} is done!\n"
25
+ msg += "#{message.command_short_name} has completed.\nCommand: #{message.command}\nTime: #{message.time_string}\n"
26
+ msg
27
+ end
28
+
29
+ def can_alert?
30
+ rtn = true
31
+ rtn &= options[:username]
32
+ rtn &= options[:password]
33
+ rtn &= options[:to]
34
+ rtn
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,40 @@
1
+ module Blertr
2
+ class Message
3
+ SECS_IN_MIN = 60
4
+ MIN_IN_HOUR = 60
5
+ SEC_RANGE = (2..59)
6
+ ONE_MIN_RANGE = (60..119)
7
+ MINS_RANGE = (120..(SECS_IN_MIN * MIN_IN_HOUR - 1))
8
+ attr_accessor :command, :seconds
9
+
10
+ def initialize command, time
11
+ self.command = command.strip
12
+ self.seconds = time.to_i
13
+ end
14
+
15
+ def command_short_name
16
+ self.command.split(/ /)[0]
17
+ end
18
+
19
+ def time_string
20
+ case seconds
21
+ when 1
22
+ "1 second"
23
+ when 0, SEC_RANGE
24
+ "#{seconds} seconds"
25
+ when ONE_MIN_RANGE
26
+ "1 minute"
27
+ when MINS_RANGE
28
+ mins = seconds / SECS_IN_MIN
29
+ "#{mins} minutes"
30
+ else
31
+ hours = (seconds.to_f / SECS_IN_MIN.to_f / MIN_IN_HOUR.to_f).round(2)
32
+ if hours == 1.0
33
+ "1 hour"
34
+ else
35
+ "#{hours} hours"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,50 @@
1
+ require 'yaml'
2
+ require 'blertr/options'
3
+
4
+ module Blertr
5
+ class Notifier
6
+ attr_reader :names
7
+ def initialize
8
+ @names = []
9
+ end
10
+
11
+ def name
12
+ (!@names or @names.empty?) ? nil : @names[0]
13
+ end
14
+
15
+ def options
16
+ @options ||= Options::options_for name
17
+ @options
18
+ end
19
+
20
+ def set_time new_time
21
+ opts = options
22
+ opts[:time] = new_time
23
+ Options::save_options_for name, opts
24
+ end
25
+
26
+ def will_alert? name, time
27
+ rtn = self.can_alert?
28
+ if rtn
29
+ rtn = in_time_window? time
30
+ end
31
+ rtn
32
+ end
33
+
34
+ def alert message
35
+ end
36
+
37
+ def in_time_window? time
38
+ rtn = false
39
+ time_min = options[:time]
40
+ if time_min and time >= time_min
41
+ rtn = true
42
+ end
43
+ rtn
44
+ end
45
+
46
+ def can_alert?
47
+ false
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ require 'fileutils'
2
+
3
+ module Blertr
4
+ class Options
5
+ def self.options_for name
6
+ rtn = {}
7
+ if File.exists? config_file_for(name)
8
+ yaml_data = YAML::load(open(config_file_for(name)))
9
+ if yaml_data
10
+ rtn = Hash[yaml_data.map {|k,v| [k.to_sym, v]}]
11
+ end
12
+ end
13
+ rtn
14
+ end
15
+
16
+ def self.save_options_for name, new_options
17
+ file = config_file_for name
18
+ File.open(file, 'w') do |file|
19
+ file.puts(YAML::dump(new_options))
20
+ end
21
+ end
22
+
23
+ def self.remove_optons_for name
24
+ file = config_file_for name
25
+ if File.exists? file
26
+ FileUtils.rm(file)
27
+ end
28
+ end
29
+
30
+ def self.config_path
31
+ File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "config"))
32
+ end
33
+
34
+ def self.config_file_for name
35
+ if name
36
+ File.join(config_path, "#{name}_config.yaml")
37
+ else
38
+ ""
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ module Blertr
2
+ class TimeParser
3
+ SECONDS_IN_MIN = 60
4
+ SECONDS_IN_HOUR = 3600
5
+ SECONDS_IN_DAY = 86400
6
+
7
+ def self.to_seconds time_string
8
+ time_seconds = 0
9
+ if time_string =~ /^(\d+)$/
10
+ # only digits. assume seconds
11
+ time_seconds = $1.to_i
12
+ elsif time_string =~ /^(\d+)\s+(\w+)$/
13
+ # digits and words
14
+ digits = $1.to_i
15
+ mult = convert_word $2
16
+ time_seconds = digits * mult
17
+ end
18
+ time_seconds = time_seconds > 0 ? time_seconds : nil
19
+
20
+ time_seconds
21
+ end
22
+
23
+ def self.convert_word input_word
24
+ multiplier = 1
25
+ if input_word =~ /^s/
26
+ multiplier = 1
27
+ elsif input_word =~ /^m/
28
+ multiplier = SECONDS_IN_MIN
29
+ elsif input_word =~ /^(h|hour|hr)/
30
+ multiplier = SECONDS_IN_HOUR
31
+ elsif input_word =~ /^d/
32
+ multiplier = SECONDS_IN_DAY
33
+ end
34
+ multiplier
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,42 @@
1
+
2
+ require 'blertr/notifier'
3
+
4
+ module Blertr
5
+ class TwitterNotifier < Notifier
6
+ def initialize
7
+ super
8
+ @names = ["twitter", "tweet", "twit"]
9
+ end
10
+
11
+ def alert message
12
+ Twitter.configure do |config|
13
+ config.consumer_key = options[:consumer_key]
14
+ config.consumer_secret = options[:consumer_secret]
15
+ config.oauth_token = options[:oauth_token]
16
+ config.oauth_token_secret = options[:oauth_token_secret]
17
+ end
18
+ msg = message message.command_short_name, command.time_string
19
+ Twitter.update(msg)
20
+ end
21
+
22
+ def message name, time
23
+ user = options[:to].nil? ? "" : "@#{options[:to]}"
24
+ msg = "#{user} #{name} is done! Took #{time}"
25
+ msg
26
+ end
27
+
28
+ def can_alert?
29
+ rtn = true
30
+ begin
31
+ require 'rubygems'
32
+ require 'twitter'
33
+ rescue LoadError => e
34
+ rtn = false
35
+ end
36
+ if rtn
37
+ [:consumer_key, :consumer_secret, :oauth_token, :oauth_token_secret].each { |key| rtn &= options[key]}
38
+ end
39
+ rtn
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ module Blertr
2
+ VERSION = "0.1.0".freeze
3
+ end