1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
module Sentry
FILE_TIMESTAMPS = {} of String => String # {file => timestamp}
class ProcessRunner
getter app_process : (Nil | Process) = nil
property process_name : String
property should_build = true
property files = [] of String
def initialize(
@process_name : String,
@build_command : String,
@run_command : String,
@build_args : Array(String) = [] of String,
@run_args : Array(String) = [] of String,
files = [] of String,
should_build = true
)
@files = files
@should_build = should_build
@should_kill = false
@app_built = false
end
private def build_app_process
puts "🤖 compiling #{process_name}..."
build_args = @build_args
if build_args.size > 0
Process.run(@build_command, build_args, shell: true, output: Process::Redirect::Inherit, error: Process::Redirect::Inherit)
else
Process.run(@build_command, shell: true, output: Process::Redirect::Inherit, error: Process::Redirect::Inherit)
end
end
private def create_app_process
app_process = @app_process
if app_process.is_a? Process
unless app_process.terminated?
puts "🤖 killing #{process_name}..."
app_process.kill
end
end
puts "🤖 starting #{process_name}..."
run_args = @run_args
if run_args.size > 0
@app_process = Process.new(@run_command, run_args, output: Process::Redirect::Inherit, error: Process::Redirect::Inherit)
else
@app_process = Process.new(@run_command, output: Process::Redirect::Inherit, error: Process::Redirect::Inherit)
end
end
private def get_timestamp(file : String)
File.stat(file).mtime.to_s("%Y%m%d%H%M%S")
end
# Compiles and starts the application
#
def start_app
return create_app_process unless @should_build
build_result = build_app_process()
if build_result && build_result.success?
@app_built = true
create_app_process()
elsif !@app_built # if build fails on first time compiling, then exit
puts "🤖 Compile time errors detected. SentryBot shutting down..."
exit 1
end
end
# Scans all of the `@files`
#
def scan_files
file_changed = false
app_process = @app_process
files = @files
Dir.glob(files) do |file|
timestamp = get_timestamp(file)
if FILE_TIMESTAMPS[file]? && FILE_TIMESTAMPS[file] != timestamp
FILE_TIMESTAMPS[file] = timestamp
file_changed = true
puts "🤖 #{file}"
elsif FILE_TIMESTAMPS[file]?.nil?
puts "🤖 watching file: #{file}"
FILE_TIMESTAMPS[file] = timestamp
file_changed = true if (app_process && !app_process.terminated?)
end
end
start_app() if (file_changed || app_process.nil?)
end
def run
puts "🤖 Your SentryBot is vigilant. beep-boop..."
loop do
if @should_kill
puts "🤖 Powering down your SentryBot..."
break
end
scan_files
sleep 1
end
end
def kill
@should_kill = true
end
end
end
|