ak47 0.1.0 → 0.2.1
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/README.md +20 -2
- data/ak47.gemspec +1 -0
- data/lib/ak47.rb +41 -25
- data/lib/ak47/runner.rb +48 -0
- data/lib/ak47/version.rb +1 -1
- metadata +19 -4
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Ak47
|
2
2
|
|
3
|
-
|
3
|
+
Ak47 is a general purpose reloader. It allows you to reload any command line argument based on either time or
|
4
|
+
file system change events. File system change events are only supported on Windows, Mac, and Linux.
|
4
5
|
|
5
6
|
## Installation
|
6
7
|
|
@@ -8,4 +9,21 @@ Reload anything. Watches the current directory for file changes and restarts you
|
|
8
9
|
|
9
10
|
## Usage
|
10
11
|
|
11
|
-
|
12
|
+
To start an application using ak47, just prepend the entire command with ak47. For example:
|
13
|
+
|
14
|
+
ak47 bundle exec thin -R config.ru start
|
15
|
+
|
16
|
+
This will run your webserver, but will reload it if there are any changes in your working directory.
|
17
|
+
|
18
|
+
There are a few command line options as well:
|
19
|
+
|
20
|
+
* -m / --maximum Maximum time to wait before restarting, if unspecified wait forever.
|
21
|
+
* -i / --interval Interval of time to wait before restarting in the event of a restart. Defaults to 0.01 seconds.
|
22
|
+
* -e / --error-time Amount of time to wait between restarts if there was an error. Defaults to 5 seconds.
|
23
|
+
|
24
|
+
Any remaining arguments passed to the path will be interpretted as directories to watch. To stop parsing command line arguments
|
25
|
+
and enter your command, use `--` to seperate options from your command. For example:
|
26
|
+
|
27
|
+
ak47 -i2 test -- rake test
|
28
|
+
|
29
|
+
This will watch your `test` directory and wait two seconds between restarts.
|
data/ak47.gemspec
CHANGED
data/lib/ak47.rb
CHANGED
@@ -1,40 +1,56 @@
|
|
1
1
|
require 'guard'
|
2
2
|
require 'shell_tools'
|
3
3
|
require "ak47/version"
|
4
|
+
require "ak47/runner"
|
5
|
+
require "smart_colored/extend"
|
4
6
|
|
5
7
|
module Ak47
|
6
8
|
Reload = Class.new(RuntimeError)
|
7
9
|
|
8
10
|
class << self
|
9
11
|
def run(*argv)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
at_exit { Process.kill("INT", @pid) rescue nil if @pid }
|
12
|
+
argv_opts, commands = if argv == ['--help'] or argv == ['-help']
|
13
|
+
[argv, []]
|
14
|
+
elsif divider_index = argv.index('--')
|
15
|
+
[argv[0...divider_index], argv[divider_index.succ...argv.size]]
|
16
|
+
else
|
17
|
+
[[], argv]
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
rescue Reload
|
35
|
-
puts "[Reloading... #{Time.new.to_s}]"
|
20
|
+
interval, maximum, error_time = 0.01, nil, 5
|
21
|
+
optparse = OptionParser.new do |opts|
|
22
|
+
opts.banner = "Usage: ak47 [cmd] / ak47 [options] -- [cmd]"
|
23
|
+
opts.on( '-i', '--interval [FLOAT]', 'Interval before restarting' ) do |i|
|
24
|
+
interval = Float(i) rescue raise("Interval must be a valid floating point number (e.g. -i0.5)")
|
25
|
+
raise("Interval must be a positive number") unless interval >= 0
|
26
|
+
end
|
27
|
+
opts.on( '-m', '--maximum [FLOAT]', 'Maximum time to wait before restarting' ) do |m|
|
28
|
+
maximum = Float(m) rescue raise("Maximum must be a valid floating point number (e.g. -m60)")
|
29
|
+
raise("Maximum must be a positive number") unless maximum >= 0
|
30
|
+
end
|
31
|
+
opts.on( '-e', '--error-time [FLOAT]', 'Maximum time to wait before restarting if there was an abnormal status code' ) do |e|
|
32
|
+
error_time = Float(e) rescue raise("Error time must be a valid floating point number (e.g. -e10)")
|
33
|
+
raise("Maximum must be a positive number") unless error_time >= 0
|
36
34
|
end
|
35
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
36
|
+
puts opts
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
end
|
40
|
+
optparse.parse!(argv_opts)
|
41
|
+
watch_dirs = argv_opts
|
42
|
+
watch_dirs << Dir.pwd if watch_dirs.empty?
|
43
|
+
watch_dirs.map! { |wd| File.expand_path(wd, Dir.pwd) }
|
44
|
+
|
45
|
+
command = ShellTools.escape(commands).strip
|
46
|
+
if command.empty?
|
47
|
+
puts optparse
|
48
|
+
puts
|
49
|
+
raise "No command supplied"
|
37
50
|
end
|
51
|
+
Runner.new(watch_dirs, command, maximum, interval, error_time).start
|
52
|
+
rescue
|
53
|
+
puts $!.message.red
|
38
54
|
end
|
39
55
|
end
|
40
56
|
end
|
data/lib/ak47/runner.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Ak47
|
2
|
+
class Runner
|
3
|
+
attr_reader :watch_dirs, :command, :maximum, :interval, :error_time
|
4
|
+
|
5
|
+
def initialize(watch_dirs, command, maximum, interval, error_time)
|
6
|
+
@watch_dirs, @command, @maximum, @interval, @error_time = watch_dirs, command, maximum, interval, error_time
|
7
|
+
end
|
8
|
+
|
9
|
+
def start
|
10
|
+
listeners = watch_dirs.map {|wd| Guard::Listener.select_and_init(:watchdir => wd, :watch_all_modifications => true) }
|
11
|
+
listeners.each do |l|
|
12
|
+
l.on_change { |f| Thread.main.raise Reload, "File system changed" }
|
13
|
+
Thread.new { l.start }
|
14
|
+
end
|
15
|
+
|
16
|
+
at_exit { Process.kill("INT", @pid) rescue nil if @pid }
|
17
|
+
|
18
|
+
puts "[Starting ak47 #{VERSION} in #{watch_dirs.join(', ')}]".green
|
19
|
+
loop do
|
20
|
+
begin
|
21
|
+
puts "[Running... #{Time.new.to_s}]".yellow
|
22
|
+
puts "# #{command}"
|
23
|
+
if maximum
|
24
|
+
@thread = Thread.new { sleep maximum; Thread.main.raise Reload, "Cancelled due to maximum time" }
|
25
|
+
end
|
26
|
+
@pid = fork {
|
27
|
+
exec(command)
|
28
|
+
}
|
29
|
+
_, status = Process.waitpid2(@pid)
|
30
|
+
@thread.kill if @thread
|
31
|
+
if status.success?
|
32
|
+
puts "[Terminated, waiting for file system change]".green
|
33
|
+
maximum ? sleep(interval) : sleep
|
34
|
+
else
|
35
|
+
puts "[Terminated abnormally (#{status.inspect}), retrying in 5s]".red
|
36
|
+
sleep error_time
|
37
|
+
end
|
38
|
+
rescue Reload => e
|
39
|
+
sleep interval
|
40
|
+
puts "[Reloading (#{e.message}) #{Time.new.to_s}]".yellow
|
41
|
+
rescue Interrupt
|
42
|
+
puts "[Interrupted, exiting]".yellow
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/ak47/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ak47
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 2
|
8
9
|
- 1
|
9
|
-
|
10
|
-
version: 0.1.0
|
10
|
+
version: 0.2.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Josh Hull
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-01-
|
18
|
+
date: 2012-01-06 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: guard
|
@@ -49,6 +49,20 @@ dependencies:
|
|
49
49
|
version: 0.1.0
|
50
50
|
type: :runtime
|
51
51
|
version_requirements: *id002
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: smart_colored
|
54
|
+
prerelease: false
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
type: :runtime
|
65
|
+
version_requirements: *id003
|
52
66
|
description: Reload anything.
|
53
67
|
email:
|
54
68
|
- joshbuddy@gmail.com
|
@@ -66,6 +80,7 @@ files:
|
|
66
80
|
- ak47.gemspec
|
67
81
|
- bin/ak47
|
68
82
|
- lib/ak47.rb
|
83
|
+
- lib/ak47/runner.rb
|
69
84
|
- lib/ak47/version.rb
|
70
85
|
homepage: ""
|
71
86
|
licenses: []
|