Watcher plugin fixes
* com.noccy.watcher: Initial inotify support * ScriptRunner now accepts an array of local vars for expansion when evaluating scripts
This commit is contained in:
parent
30dfd4889b
commit
1125ccb82d
@ -17,10 +17,12 @@ class FileWatcher {
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (extension_loaded('inotify')) {
|
||||
$this->monitor = new MtimeMonitor();
|
||||
//$this->monitor = new InotifyMonitor();
|
||||
if (extension_loaded('inotify') && !getenv("SPARK_NO_INOTIFY")) {
|
||||
//$this->monitor = new MtimeMonitor();
|
||||
printf("Enabling inotify support, watching directories\n");
|
||||
$this->monitor = new InotifyMonitor();
|
||||
} else {
|
||||
printf("No inotify support, watching file mtimes\n");
|
||||
$this->monitor = new MtimeMonitor();
|
||||
}
|
||||
$this->scriptRunner = get_environment()->getScriptRunner();
|
||||
@ -38,7 +40,11 @@ class FileWatcher {
|
||||
private function triggerRule(Rule $rule)
|
||||
{
|
||||
$actions = $rule->getActions();
|
||||
$this->scriptRunner->evaluate($actions);
|
||||
$locals = [
|
||||
'WATCHER_RULE' => $rule->getName(),
|
||||
'WATCHER_FILES' => join(" ",$rule->getWatchedFiles()),
|
||||
];
|
||||
$this->scriptRunner->evaluate($actions, $locals);
|
||||
}
|
||||
|
||||
public function loop()
|
||||
|
97
plugins/com.noccy.watcher/Monitor/InotifyMonitor.php
Normal file
97
plugins/com.noccy.watcher/Monitor/InotifyMonitor.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace SparkPlug\Com\Noccy\Watcher\Monitor;
|
||||
|
||||
use SparkPlug\Com\Noccy\Watcher\Rule;
|
||||
|
||||
class InotifyMonitor implements MonitorInterface
|
||||
{
|
||||
private array $rules = [];
|
||||
|
||||
private array $watched = [];
|
||||
|
||||
private array $modified = [];
|
||||
|
||||
private $fd;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->fd = \inotify_init();
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (is_resource($this->fd)) fclose($this->fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function add(Rule $rule)
|
||||
{
|
||||
$this->rules[] = $rule;
|
||||
|
||||
$paths = $rule->getWatchedFiles();
|
||||
$check = [];
|
||||
foreach ($paths as $path) {
|
||||
if (str_contains($path, '*')) {
|
||||
$check = array_merge($check, glob($path));
|
||||
} else {
|
||||
$check[] = $path;
|
||||
}
|
||||
}
|
||||
$dirs = [];
|
||||
foreach ($check as $path) {
|
||||
$dir = is_dir($path) ? $path : dirname($path);
|
||||
if (!array_key_exists($dir, $dirs)) {
|
||||
$dirs[$dir] = $rule;
|
||||
\inotify_add_watch($this->fd, $dir, \IN_ATTRIB);
|
||||
}
|
||||
}
|
||||
$this->watched = array_merge($this->watched, $dirs);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getModified(): array
|
||||
{
|
||||
$mod = $this->modified;
|
||||
$this->modified = [];
|
||||
return $mod;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getWatched(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function loop()
|
||||
{
|
||||
$read = [ $this->fd ];
|
||||
$write = null;
|
||||
$except = null;
|
||||
$changed = [];
|
||||
while (stream_select($read,$write,$except,0)) {
|
||||
$events = \inotify_read($this->fd);
|
||||
foreach ($events as $event) {
|
||||
$changed[] = $event['name'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($changed as $file) {
|
||||
foreach ($this->watched as $dir=>$rule) {
|
||||
if (file_exists($dir."/".$file)) {
|
||||
if (!in_array($rule, $this->modified)) {
|
||||
printf("~ modified: %s (%s)\n", $dir."/".$file, $rule->getName());
|
||||
$this->modified[] = $rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -60,12 +60,13 @@ class MtimeMonitor implements MonitorInterface
|
||||
}
|
||||
|
||||
foreach ($check as $path) {
|
||||
if (!file_exists($path)) continue;
|
||||
if (empty($this->watched[$path])) {
|
||||
$this->watched[$path] = filemtime($path);
|
||||
} else {
|
||||
$mtime = filemtime($path);
|
||||
if ($mtime > $this->watched[$path]) {
|
||||
printf("* modified: %s (%s)\n", $path, $rule->getName());
|
||||
printf("~ modified: %s (%s)\n", $path, $rule->getName());
|
||||
$this->watched[$path] = $mtime;
|
||||
if (!in_array($rule, $this->modified)) {
|
||||
$this->modified[] = $rule;
|
||||
|
@ -34,4 +34,21 @@ issues.
|
||||
}
|
||||
```
|
||||
|
||||
The `initial-trigger` key controls whether the rule is triggered on startup.
|
||||
- `name` contains an optional name of the rule.
|
||||
- `initial-trigger` controls whether the rule is triggered on startup. If false
|
||||
or not specified, the actions will be triggered when the file is modified
|
||||
after startup.
|
||||
- `watch` is an array of files or wildcards to watch.
|
||||
- `actions` are script actions to invoke.
|
||||
|
||||
The executed action will have access to the `WATCHER_RULE` and `WATCHER_FILES`
|
||||
variables for expansion.
|
||||
|
||||
## Known issues
|
||||
|
||||
- The *inotify* monitor will trigger whenever a file is changed in a watched
|
||||
directory, even if an explicit file is set. For example, changing the file
|
||||
`./templates/index.html` will trigger the rule for `./templates/style.scss`.
|
||||
If you can't live with that, export `SPARK_NO_INOTIFY=1` before invoking!
|
||||
- The *mtime* monitor will poll the mtime of each watched file every check.
|
||||
This works great if you are explicit in what you are watching.
|
||||
|
@ -26,16 +26,16 @@ class ScriptRunner
|
||||
$this->evaluate($script);
|
||||
}
|
||||
|
||||
public function evaluate(string|array $script)
|
||||
public function evaluate(string|array $script, array $locals=[])
|
||||
{
|
||||
if (is_array($script)) {
|
||||
foreach ($script as $step) {
|
||||
$this->evaluate($step);
|
||||
$this->evaluate($step, $locals);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$script = $this->expandString($script);
|
||||
$script = $this->expandString($script, $locals);
|
||||
|
||||
// Determine what to do
|
||||
if (str_starts_with($script, '@')) {
|
||||
@ -81,10 +81,12 @@ class ScriptRunner
|
||||
}
|
||||
}
|
||||
|
||||
public function expandString(string $input)
|
||||
public function expandString(string $input, array $locals=[])
|
||||
{
|
||||
return preg_replace_callback('/(\$\{(.+?)\})/', function ($match) {
|
||||
|
||||
return preg_replace_callback('/(\$\{(.+?)\})/', function ($match) use ($locals) {
|
||||
if (array_key_exists($match[2], $locals)) {
|
||||
return $locals[$match[2]];
|
||||
}
|
||||
return ($_ENV[$match[2]]??getenv($match[2]))??null;
|
||||
}, $input);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user