blertr 0.1.0

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