rehctaw 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +41 -0
- data/bin/rehctaw +103 -0
- metadata +48 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 52bdd0357b77fbd19825f9cbe698a35ba024ba87
|
4
|
+
data.tar.gz: 1f584f7e65da9fa005c19b4aa3ecf886439ce991
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3d7a13db6f39cdb4bfe59f47b0191eb538c08165084645f3830ecd2d61b4b9ea672fa835256b673c75d14775f519c21ce444ddd567ea4c6affb4d46375085d7c
|
7
|
+
data.tar.gz: 266fed86851ed1a113c1c53333f60138df14a502b7fcc2bc94c005f42b271a166ab082dbcc35716524bdbf7f53f71b66323eb479364bfcac4c8d6fe76e9fccb5
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
## Name
|
2
|
+
|
3
|
+
`rehctaw` - Execute system commands according to file contents.
|
4
|
+
|
5
|
+
## Description
|
6
|
+
|
7
|
+
`rehctaw` watches contents of a file, and executes system commands
|
8
|
+
according to those contents. The commands, intervals, ... are provided
|
9
|
+
in a YAML configuration file which is also watched.
|
10
|
+
|
11
|
+
## Example
|
12
|
+
|
13
|
+
The sample configuration file can be found under `./examples/` directory.
|
14
|
+
To use this example, type
|
15
|
+
|
16
|
+
$ cp ./examples/simple.yaml ./examples/mine.yaml
|
17
|
+
$ ./bin/rehctaw ./examples/mine.yaml
|
18
|
+
$ echo foobar > /tmp/watcher
|
19
|
+
$ echo reload > /tmp/watcher
|
20
|
+
|
21
|
+
You can update the file `./examples/mine.yaml`. The program will use
|
22
|
+
new settings in the next run.
|
23
|
+
|
24
|
+
## License
|
25
|
+
|
26
|
+
MIT
|
27
|
+
|
28
|
+
## Author
|
29
|
+
|
30
|
+
Anh K. Huynh
|
31
|
+
|
32
|
+
## History
|
33
|
+
|
34
|
+
The idea comes from some `Rails` framework. When a `Rails` application
|
35
|
+
is running, you can quickly send a `reload` signal to it, by touching
|
36
|
+
a file. See [ChiliProject][] for an example.
|
37
|
+
|
38
|
+
I don't want to use `inotify`, because that works at file system level
|
39
|
+
and it may cause some issues when the file is renamed.
|
40
|
+
|
41
|
+
[ChiliProject]: https://www.chiliproject.org/projects/chiliproject/wiki/Restart_ChiliProject
|
data/bin/rehctaw
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Purpose: Execute something according to contents of a file
|
4
|
+
# Author : Anh K. Huynh
|
5
|
+
# License: MIT
|
6
|
+
# Date : 2015 Feb 25
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'yaml'
|
10
|
+
require 'timeout'
|
11
|
+
rescue => e
|
12
|
+
STDERR.puts ":: Error: #{e}"
|
13
|
+
exit 127
|
14
|
+
end
|
15
|
+
|
16
|
+
GLOBAL_WATCHER = {
|
17
|
+
"mtime" => 0
|
18
|
+
}
|
19
|
+
|
20
|
+
_default_watcher = {
|
21
|
+
"interval" => 5,
|
22
|
+
"stop" => "/bin/true",
|
23
|
+
"start" => "/bin/true",
|
24
|
+
"restart" => "/bin/true",
|
25
|
+
"reset" => "/bin/true",
|
26
|
+
"action" => "",
|
27
|
+
"file" => "/dev/null",
|
28
|
+
"mtime" => 0,
|
29
|
+
"timeout" => 10
|
30
|
+
}
|
31
|
+
|
32
|
+
def _say(something)
|
33
|
+
STDERR.puts ":: #{something}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def _configuration_rescan(watcher, config_file)
|
37
|
+
return watcher unless File.file?(config_file) and File.readable?(config_file)
|
38
|
+
|
39
|
+
new_mtime = File.stat(config_file).mtime.to_i
|
40
|
+
|
41
|
+
if new_mtime != GLOBAL_WATCHER["mtime"]
|
42
|
+
GLOBAL_WATCHER["mtime"] = new_mtime
|
43
|
+
begin
|
44
|
+
new_watcher = YAML.load_file(config_file)
|
45
|
+
watcher.merge!(new_watcher["watcher"])
|
46
|
+
watcher["interval"] = [1, watcher["interval"].to_i.abs].max
|
47
|
+
watcher["timeout"] = [1, watcher["timeout"].to_i.abs].max
|
48
|
+
|
49
|
+
_say "Info: Config reload => #{new_watcher.inspect}"
|
50
|
+
rescue => e
|
51
|
+
_say "Error: #{e}"
|
52
|
+
return watcher
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
return watcher
|
57
|
+
end
|
58
|
+
|
59
|
+
if ARGV.size < 1
|
60
|
+
_say "Error: Missing configuration file"
|
61
|
+
exit 127
|
62
|
+
end
|
63
|
+
|
64
|
+
GLOBAL_WATCHER["file"] = ARGV.first
|
65
|
+
watcher = _configuration_rescan(_default_watcher, GLOBAL_WATCHER["file"])
|
66
|
+
|
67
|
+
while true
|
68
|
+
executable = false
|
69
|
+
|
70
|
+
if File.file?(watcher["file"]) and File.readable?(watcher["file"])
|
71
|
+
new_mtime = File.stat(watcher["file"]).mtime.to_i
|
72
|
+
if new_mtime != watcher["mtime"]
|
73
|
+
executable = true if watcher["mtime"] > 0
|
74
|
+
watcher["mtime"] = new_mtime
|
75
|
+
# FIXME: reading the whole file may not a good idea. It's slow
|
76
|
+
# FIXME: should find a way to read the first line of a file.
|
77
|
+
new_action = File.readlines(watcher["file"]).first.to_s.strip
|
78
|
+
watcher["action"] = new_action
|
79
|
+
end
|
80
|
+
else
|
81
|
+
_say "Error: Action file '#{watcher["file"]}' unreadable"
|
82
|
+
end
|
83
|
+
|
84
|
+
if executable
|
85
|
+
if watcher[watcher["action"]]
|
86
|
+
command = watcher[watcher["action"]]
|
87
|
+
_say "Info: Executing (#{watcher["action"]}) '#{command}'"
|
88
|
+
begin
|
89
|
+
Timeout::timeout(watcher["timeout"]) do
|
90
|
+
ret = system("#{command}")
|
91
|
+
end
|
92
|
+
_say "Info: Execution complete"
|
93
|
+
rescue Timeout::Error => e
|
94
|
+
_say "Error: Timeout reachable (#{watcher["timeout"]}s)"
|
95
|
+
end
|
96
|
+
else
|
97
|
+
_say "Error: Invalid action: #{watcher["action"]}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
sleep(watcher["interval"])
|
102
|
+
watcher = _configuration_rescan(watcher, GLOBAL_WATCHER["file"])
|
103
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rehctaw
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anh K. Huynh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-26 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: "`rehctaw` watches contents of a file, and executes system commands according
|
14
|
+
to those contents. The commands, intervals, ... are provided in a YAML configuration
|
15
|
+
file which is also watched."
|
16
|
+
email: kyanh@theslinux.org
|
17
|
+
executables:
|
18
|
+
- rehctaw
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- README.md
|
23
|
+
- bin/rehctaw
|
24
|
+
homepage: https://github.com/icy/rehctaw
|
25
|
+
licenses:
|
26
|
+
- MIT
|
27
|
+
metadata: {}
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 2.4.5
|
45
|
+
signing_key:
|
46
|
+
specification_version: 4
|
47
|
+
summary: "`rehctaw` executes system commands according to file contents"
|
48
|
+
test_files: []
|