rehctaw 1.1.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.
- 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: []
|