lmk 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.md +31 -0
- data/bin/lmk +7 -0
- data/lib/lmk.rb +8 -0
- data/lib/lmk/cli.rb +28 -0
- data/lib/lmk/config.rb +52 -0
- data/lib/lmk/gist_sender.rb +27 -0
- data/lib/lmk/runner.rb +64 -0
- data/lib/lmk/shell_command.rb +70 -0
- data/lib/lmk/twilio_client_wrapper.rb +26 -0
- data/lib/lmk/twilio_sender.rb +16 -0
- data/lib/lmk/version.rb +3 -0
- data/lmk.gemspec +15 -0
- metadata +59 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Luke Winikates
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
[![Code Climate](https://codeclimate.com/github/LukeWinikates/lmk.png)](https://codeclimate.com/github/LukeWinikates/lmk)
|
2
|
+
[![Build Status](https://travis-ci.org/LukeWinikates/lmk.png?branch=master)](https://travis-ci.org/LukeWinikates/lmk)
|
3
|
+
LMK
|
4
|
+
===========
|
5
|
+
|
6
|
+
Don't sit around waiting for rake/make/tests/etc to finish. Let the machine tell you when it's done.
|
7
|
+
|
8
|
+
## PREREQUISITES:
|
9
|
+
You need a twilio account, including API Key and Account SID for sending [SMSes](http://www.twilio.com/sms).
|
10
|
+
|
11
|
+
## USAGE:
|
12
|
+
`$ lmk exec [command]`
|
13
|
+
|
14
|
+
executes [command], sending a digest of the result as an SMS to the specified phone number and creating a private, anonymous gist with the full command output.
|
15
|
+
|
16
|
+
For example:
|
17
|
+
`$ lmk exec bundle install`
|
18
|
+
|
19
|
+
## INSTALLATION/CONFIGURATION:
|
20
|
+
LMK requires a ~/.lmkrc file in order to run. The .lmkrc is a simple YAML file with four required values:
|
21
|
+
- phone_number: The number at which you want to receive a message when the command has finished running.
|
22
|
+
- from: a number associated with your Twilio account & set up for SMS sending
|
23
|
+
- account_sid: from your Twilio Account
|
24
|
+
- auth_token: from your Twilio Account
|
25
|
+
|
26
|
+
You can validate your .lmkrc at any time by running LMK's `config` command:
|
27
|
+
|
28
|
+
`$ lmk config`
|
29
|
+
|
30
|
+
## LICENSE:
|
31
|
+
MIT Licensed. See LICENSE file.
|
data/bin/lmk
ADDED
data/lib/lmk.rb
ADDED
data/lib/lmk/cli.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module LMK
|
4
|
+
class CLI < ::Thor
|
5
|
+
desc "exec COMMAND", "run a command and get an SMS with its result"
|
6
|
+
def exec(*command)
|
7
|
+
command = command.join ' '
|
8
|
+
Runner.run(command, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "config", "read the current twilio config file"
|
12
|
+
def config
|
13
|
+
Kernel.puts Config.from_file.debug
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "debug COMMAND", "view template output for the given command"
|
17
|
+
def debug(*command)
|
18
|
+
command = command.join ' '
|
19
|
+
cmd = ShellCommand.new(command).tap do |c|
|
20
|
+
c.html_url = "http://gist.example.com"
|
21
|
+
end
|
22
|
+
puts "concise"
|
23
|
+
puts cmd.concise_output
|
24
|
+
puts "\n\nfull"
|
25
|
+
puts cmd.full_output
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/lmk/config.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'hashie'
|
3
|
+
|
4
|
+
module LMK
|
5
|
+
class Config
|
6
|
+
def self.default_path
|
7
|
+
"#{ENV['HOME']}/.lmkrc"
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.from_file(path = default_path)
|
11
|
+
attrs = ::YAML.load_file(path) if File.exists?(path)
|
12
|
+
new(attrs, path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(attributes, file = nil)
|
16
|
+
(attributes || {}).each do |k, v|
|
17
|
+
setter = "#{k}=".to_sym
|
18
|
+
send(setter, v) if respond_to?(setter)
|
19
|
+
end
|
20
|
+
@file = file
|
21
|
+
end
|
22
|
+
|
23
|
+
def valid?
|
24
|
+
required_attributes.map { |attr| send(attr) }.all?
|
25
|
+
end
|
26
|
+
|
27
|
+
def required_attributes
|
28
|
+
[:auth_token, :from, :phone_number, :account_sid]
|
29
|
+
end
|
30
|
+
|
31
|
+
def missing_values
|
32
|
+
required_attributes.select { |method| send(method).nil? }
|
33
|
+
end
|
34
|
+
|
35
|
+
def debug
|
36
|
+
<<-RESULT
|
37
|
+
LMK Configuration #{valid? ? 'valid' : 'invalid'}
|
38
|
+
#{'Config file missing, create ' + @file + ' with required values.' if @file && !File.exists?(@file) }
|
39
|
+
missing values: #{valid? ? 'none' : missing_values }
|
40
|
+
#{raw}
|
41
|
+
RESULT
|
42
|
+
end
|
43
|
+
|
44
|
+
def raw
|
45
|
+
instance_variables.map do |ivar|
|
46
|
+
"#{ivar.to_s.gsub("@", "")}: #{instance_variable_get ivar}"
|
47
|
+
end.join "\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_accessor :auth_token, :from, :phone_number, :account_sid
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'octokit'
|
2
|
+
|
3
|
+
module LMK
|
4
|
+
class GistSender
|
5
|
+
def send(commmand)
|
6
|
+
result = client.create_gist options(commmand)
|
7
|
+
commmand.html_url = result[:html_url]
|
8
|
+
commmand
|
9
|
+
end
|
10
|
+
|
11
|
+
def options(command)
|
12
|
+
{
|
13
|
+
:description => command.command,
|
14
|
+
:public => false,
|
15
|
+
:files => {
|
16
|
+
"#{command.timestamp.strftime '%FT%R'}.lmk" => {
|
17
|
+
:content => command.full_output
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def client
|
24
|
+
Octokit::Client.new
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/lmk/runner.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module LMK
|
2
|
+
class Runner
|
3
|
+
class Configuration
|
4
|
+
attr_accessor :sms_service, :gist_service, :console_service, :shell_service
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@sms_service = LMK::TwilioSender.new
|
8
|
+
@gist_service = LMK::GistSender.new
|
9
|
+
@console_service = Kernel
|
10
|
+
@shell_service = LMK::ShellCommand
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.configure
|
15
|
+
yield self.configuration
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.configuration
|
19
|
+
@@default_configuration ||= Configuration.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.run(command, options)
|
23
|
+
new.run(command, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(configuration = Runner.configuration)
|
27
|
+
@configuration = configuration
|
28
|
+
end
|
29
|
+
|
30
|
+
def console(message)
|
31
|
+
@configuration.console_service.puts(message)
|
32
|
+
end
|
33
|
+
|
34
|
+
def shell(command)
|
35
|
+
@configuration.shell_service.exec(command)
|
36
|
+
end
|
37
|
+
|
38
|
+
def sms(command)
|
39
|
+
@configuration.sms_service.send(command)
|
40
|
+
end
|
41
|
+
|
42
|
+
def post_to_web(command)
|
43
|
+
@configuration.gist_service.send(command)
|
44
|
+
end
|
45
|
+
|
46
|
+
def run(command, options)
|
47
|
+
return unless validate!
|
48
|
+
console("running command `#{command}`")
|
49
|
+
result = shell(command)
|
50
|
+
result = post_to_web(result)
|
51
|
+
result = sms(result)
|
52
|
+
console(result.output)
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate!
|
56
|
+
unless @configuration.sms_service.runnable?
|
57
|
+
console("Configuration invalid. Run `lmk config` for more info")
|
58
|
+
false
|
59
|
+
else
|
60
|
+
true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'popen4'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module LMK
|
5
|
+
class ShellCommand
|
6
|
+
attr_reader :command, :timestamp
|
7
|
+
attr_accessor :html_url
|
8
|
+
|
9
|
+
def initialize(command)
|
10
|
+
@timestamp = Time.now
|
11
|
+
@command = command
|
12
|
+
@status = ::POpen4.popen4(command) do |stdout, stderr, stdin, pid|
|
13
|
+
@error = stderr.read
|
14
|
+
@output = stdout.read
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_binding
|
19
|
+
binding
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.exec(command)
|
23
|
+
new(command)
|
24
|
+
end
|
25
|
+
|
26
|
+
def success?
|
27
|
+
status == 0
|
28
|
+
end
|
29
|
+
|
30
|
+
def status
|
31
|
+
@status.exitstatus
|
32
|
+
end
|
33
|
+
|
34
|
+
def output
|
35
|
+
if success?
|
36
|
+
@output
|
37
|
+
else
|
38
|
+
@error
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def concise_output
|
43
|
+
concise_template.result get_binding
|
44
|
+
end
|
45
|
+
|
46
|
+
def full_output
|
47
|
+
full_template.result get_binding
|
48
|
+
end
|
49
|
+
|
50
|
+
def full_template
|
51
|
+
ERB.new %q{
|
52
|
+
%%% LMK Command Result: %%%
|
53
|
+
> <%= command %>
|
54
|
+
<% if success? %>succeeded
|
55
|
+
<% else %> failed (<%=status%>)<% end %>
|
56
|
+
full output:
|
57
|
+
----------------------------
|
58
|
+
<%=output%>
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def concise_template
|
63
|
+
ERB.new %q{LMK Command Result:
|
64
|
+
> <%=command%>
|
65
|
+
<% if success? %>succeeded
|
66
|
+
<% else %>failed (<%=status%>)<% end %>
|
67
|
+
<% if html_url %>full result @ <%= html_url %><% end %>}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'twilio-ruby'
|
2
|
+
|
3
|
+
module LMK
|
4
|
+
class TwilioClientWrapper
|
5
|
+
def initialize(config = Config.from_file)
|
6
|
+
@config = config
|
7
|
+
@client = ::Twilio::REST::Client.new(@config.account_sid, @config.auth_token) if runnable?
|
8
|
+
end
|
9
|
+
|
10
|
+
def runnable?
|
11
|
+
@config.valid?
|
12
|
+
end
|
13
|
+
|
14
|
+
def send(message)
|
15
|
+
@client.account.sms.messages.create options.merge(:body => message)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def options
|
20
|
+
{
|
21
|
+
:from => @config.from,
|
22
|
+
:to => @config.phone_number
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module LMK
|
2
|
+
class TwilioSender
|
3
|
+
def initialize(client = TwilioClientWrapper.new)
|
4
|
+
@client = client
|
5
|
+
end
|
6
|
+
|
7
|
+
def runnable?
|
8
|
+
!!@client && @client.runnable?
|
9
|
+
end
|
10
|
+
|
11
|
+
def send(command)
|
12
|
+
@client.send command.concise_output
|
13
|
+
command
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/lmk/version.rb
ADDED
data/lmk.gemspec
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
lib = File.expand_path('../lib/', __FILE__)
|
2
|
+
$:.unshift lib unless $:.include?(lib)
|
3
|
+
|
4
|
+
require 'lmk/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'lmk'
|
8
|
+
s.summary = 'runs a command and sends the output via sms'
|
9
|
+
s.authors = ["Luke Winikates"]
|
10
|
+
s.version = LMK::VERSION
|
11
|
+
s.executables << 'lmk'
|
12
|
+
s.files = %w(LICENSE README.md lmk.gemspec)
|
13
|
+
s.files += Dir.glob("bin/**/*")
|
14
|
+
s.files += Dir.glob("lib/**/*.rb")
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lmk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Luke Winikates
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-06 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description:
|
15
|
+
email:
|
16
|
+
executables:
|
17
|
+
- lmk
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- LICENSE
|
22
|
+
- README.md
|
23
|
+
- lmk.gemspec
|
24
|
+
- bin/lmk
|
25
|
+
- lib/lmk/cli.rb
|
26
|
+
- lib/lmk/config.rb
|
27
|
+
- lib/lmk/gist_sender.rb
|
28
|
+
- lib/lmk/runner.rb
|
29
|
+
- lib/lmk/shell_command.rb
|
30
|
+
- lib/lmk/twilio_client_wrapper.rb
|
31
|
+
- lib/lmk/twilio_sender.rb
|
32
|
+
- lib/lmk/version.rb
|
33
|
+
- lib/lmk.rb
|
34
|
+
homepage:
|
35
|
+
licenses: []
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.8.16
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: runs a command and sends the output via sms
|
58
|
+
test_files: []
|
59
|
+
has_rdoc:
|