ak47 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Ak47
2
2
 
3
- Reload anything. Watches the current directory for file changes and restarts your process if anything changes.
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
- ak47 [Your original command]
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.
@@ -20,4 +20,5 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_dependency "guard", "~> 0.10.0"
22
22
  s.add_dependency "shell_tools", "~> 0.1.0"
23
+ s.add_dependency "smart_colored"
23
24
  end
@@ -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
- command = ShellTools.escape(argv)
11
- watch_dir = Dir.pwd
12
- listener = Guard::Listener.select_and_init(:watchdir => watch_dir, :watch_all_modifications => true)
13
- listener.on_change {
14
- Thread.main.raise Reload
15
- }
16
- Thread.new { listener.start }
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
- puts "[Starting ak47 #{VERSION} in #{watch_dir.inspect}]"
21
- loop do
22
- begin
23
- puts "[Running... #{Time.new.to_s}]"
24
- puts "# #{command}"
25
- @pid = fork { exec(command) }
26
- _, status = Process.waitpid2(@pid)
27
- if status.success?
28
- puts "[Terminated, waiting for file system change]"
29
- sleep
30
- else
31
- puts "[Terminated abnormally (#{status.inspect}), retrying in 5s]"
32
- sleep 5
33
- end
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Ak47
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.1"
3
3
  end
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: 27
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
+ - 2
8
9
  - 1
9
- - 0
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-04 00:00:00 Z
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: []