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 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: []