restartable 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZjBlMWMyMTgxZjllMGY4NTNkZGMzNTcxODY2ZjlmYTU5ZjA3MGNmMQ==
5
+ data.tar.gz: !binary |-
6
+ ZWE5Nzc2YjgxYTY2MjBjMDA4OGE1ZDcxZTVkNzk2Y2VlMDVmN2Q5NA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NDBkMmUxOTczOTQ5N2JlZDJjYzc1ZjMyOTc1YjgxYjNkMWMyMmEyMmJjODVl
10
+ OTlhMzA5ZTFiNmM5MWVjMjUwYzFiNDk1ZjA1ZTJiMGU0ZDQ3ZjI2ZWFlNWQx
11
+ MWYxNjRlZjZhN2Q3ZDU3YTliYjZjNjBjMTQ1YWEwMTNiMTcwYzQ=
12
+ data.tar.gz: !binary |-
13
+ NDU2NTA2M2M3N2M1YjBjZWE2ZWE5MzY5NzQxNjViYWU2ZjM1MDU3NmM2N2Ez
14
+ MGRiZDE1YTE2MmM1N2MwYmQ0NTMwMTdjZTI0ZmVmNWY4NWFhNjU5NDM0ZGEz
15
+ YTJmYjlhYWRmOGM4MDliMTQzN2Y5MGJiOTg0NDQzMmIyY2E4YWQ=
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /pkg/
2
+ /*.gem
3
+
4
+ /doc/
5
+ /rdoc/
6
+ /.yardoc/
7
+ /coverage/
8
+
9
+ Makefile
10
+ *.o
11
+ *.bundle
12
+ /tmp/
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Ivan Kuchin
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,7 @@
1
+ # restartable
2
+
3
+ Run code, Ctrl-C to restart, two Ctrl-C to stop.
4
+
5
+ ## Copyright
6
+
7
+ Copyright (c) 2012-2013 Ivan Kuchin. See LICENSE.txt for details.
data/TODO ADDED
@@ -0,0 +1,2 @@
1
+ run block on restart
2
+ bin option to run command on restart
data/bin/restartable ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require 'optparse'
5
+ require 'restartable'
6
+
7
+ options = {}
8
+ option_parser = OptionParser.new do |op|
9
+ op.banner = <<-TEXT
10
+ #{op.program_name} v#{Restartable.version}
11
+
12
+ Usege:
13
+ #{op.program_name} [options] command [arg…]
14
+
15
+ TEXT
16
+
17
+ op.on_tail('-h', '--help', 'Show full help') do
18
+ puts option_parser.help
19
+ exit
20
+ end
21
+
22
+ op.on_tail('--version', 'Show version') do
23
+ puts Restartable.version
24
+ exit
25
+ end
26
+ end
27
+
28
+ begin
29
+ option_parser.order!
30
+ raise OptionParser::ParseError, 'No command to run' if ARGV.empty?
31
+ rescue OptionParser::ParseError => e
32
+ abort "#{e.to_s}\n\n#{option_parser.help}"
33
+ end
34
+
35
+ Restartable.new(options) do
36
+ system *ARGV
37
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'sys/proctable'
4
+ require 'colored'
5
+
6
+ class Restartable
7
+ def self.version
8
+ Gem.loaded_specs['restartable'].version.to_s rescue 'DEV'
9
+ end
10
+
11
+ WAIT_SIGNALS = [[1, 'INT'], [1, 'INT'], [1, 'INT'], [1, 'TERM'], [5, 'KILL']]
12
+
13
+ def initialize(options, &block)
14
+ @options, @block = options, block
15
+ @mutex = Mutex.new
16
+ synced_trap('INT'){ interrupt! }
17
+ synced_trap('TERM'){ no_restart!; interrupt! }
18
+ cycle
19
+ end
20
+
21
+ def interrupt!
22
+ unless @interrupted
23
+ @interrupted = true
24
+ Thread.list.each do |thread|
25
+ unless Thread.current == thread
26
+ thread.raise SignalException.new('INT')
27
+ end
28
+ end
29
+ else
30
+ no_restart!
31
+ end
32
+ end
33
+
34
+ def no_restart!
35
+ @stop = true
36
+ puts 'Don\'t restart!'.red.bold
37
+ end
38
+
39
+ def cycle
40
+ until @stop
41
+ @interrupted = false
42
+ puts '^C to restart, double ^C to stop'.green
43
+ begin
44
+ @block.call
45
+ sleep # wait ^C even if block finishes
46
+ rescue SignalException
47
+ unless children.empty?
48
+ puts 'Killing children…'.yellow.bold
49
+ ripper = Thread.new do
50
+ WAIT_SIGNALS.each do |time, signal|
51
+ sleep time
52
+ puts "…SIG#{signal}…".yellow
53
+ children.each do |child|
54
+ Process.kill(signal, child.pid)
55
+ end
56
+ end
57
+ end
58
+ Process.waitall
59
+ ripper.terminate
60
+ end
61
+ unless @stop
62
+ puts 'Waiting ^C 0.5 second than restart…'.yellow.bold
63
+ sleep 0.5
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def synced_trap(signal, &block)
72
+ Signal.trap(signal) do
73
+ Thread.new do
74
+ @mutex.synchronize(&block)
75
+ end
76
+ end
77
+ end
78
+
79
+ def children
80
+ pid = Process.pid
81
+ Sys::ProcTable.ps.select{ |pe| pid == pe.ppid }
82
+ end
83
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'restartable'
5
+ s.version = '0.1.2'
6
+ s.summary = %q{Run code, Ctrl-C to restart, once more Ctrl-C to stop}
7
+ s.homepage = "http://github.com/toy/#{s.name}"
8
+ s.authors = ['Ivan Kuchin']
9
+ s.license = 'MIT'
10
+
11
+ s.rubyforge_project = s.name
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = %w[lib]
17
+
18
+ s.add_dependency 'colored', '~> 1.2'
19
+ s.add_dependency 'sys-proctable', '~> 0.9.3'
20
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: restartable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Ivan Kuchin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colored
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sys-proctable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.9.3
41
+ description:
42
+ email:
43
+ executables:
44
+ - restartable
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - LICENSE.txt
50
+ - README.markdown
51
+ - TODO
52
+ - bin/restartable
53
+ - lib/restartable.rb
54
+ - restartable.gemspec
55
+ homepage: http://github.com/toy/restartable
56
+ licenses:
57
+ - MIT
58
+ metadata: {}
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project: restartable
75
+ rubygems_version: 2.0.3
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: Run code, Ctrl-C to restart, once more Ctrl-C to stop
79
+ test_files: []