Skip to content

Instantly share code, notes, and snippets.

@uestla
Last active August 29, 2023 15:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uestla/ca907c042df7b72120286c6fd8391bc1 to your computer and use it in GitHub Desktop.
Save uestla/ca907c042df7b72120286c6fd8391bc1 to your computer and use it in GitHub Desktop.
Run command when any file in working directory changes (recursive check)
#!/usr/bin/env php
<?php
declare(strict_types = 1);
namespace Scripts;
// run given command when any file changes in given paths or in working directory
if (!isset($_SERVER['argv'][1])) {
fwrite(STDOUT, 'Usage:
' . basename(__FILE__) . ' [<path_1=cwd> [, <path_2>, ...]] <command>' . "\n");
exit(1);
}
(static function (): void {
$cwd = getcwd();
$paths = array_slice($_SERVER['argv'], 1);
$command = array_pop($paths);
if ($paths === []) {
$paths[] = '';
}
$treeHashCalculator = static function () use ($paths, $cwd): string {
$cmd = sprintf(
'find %s -type f -not -path "*/\.*" -print0 | xargs -0 sha1sum | sha1sum 2>&1', // do not check dot-files
implode(' ', array_map(static function (string $path) use ($cwd): string {
// prepend cwd for relative paths
$fullPath = strpos($path, '/') !== 0 && strpos($path, ':') === false
? rtrim(sprintf('%s/%s', $cwd, $path), '/\\')
: $path;
return escapeshellarg($fullPath);
}, $paths)),
);
$status = 0;
$output = [];
exec($cmd, $output, $status);
if ($status !== 0) {
fwrite(STDERR, '[wt] Cannot calculate content checksum - ' . implode("\n", $output) . "\n");
exit(1);
}
return trim(implode('', $output));
};
$changed = false;
$treeHash = null;
while (true) {
if ($treeHash === null) {
fwrite(STDOUT, '[wt] Calculating initial checksum ...');
}
$freshTreeHash = $treeHashCalculator();
if ($treeHash === null) {
fwrite(STDOUT, ' OK (' . $freshTreeHash . ')' . "\n");
} elseif ($treeHash !== $freshTreeHash) {
fwrite(STDOUT, '[wt] Change detected (' . $freshTreeHash . ') - running "' . $command . '" ...' . "\n\n");
$start = time();
passthru(escapeshellcmd($command));
fwrite(STDOUT, "\n" . '[wt] Done in ' . time() - $start . 's' . "\n");
$changed = true;
} else {
$changed = false;
}
if ($changed || $treeHash === null) { // message on first run or after change
fwrite(STDOUT, '[wt] Watching for changes in "' . ($paths === [''] ? $cwd : implode('", "', $paths)) . '" ...' . "\n");
}
$treeHash = $freshTreeHash;
usleep(500000); // 0.5s
}
})();
@uestla
Copy link
Author

uestla commented Oct 7, 2021

Example usage:

watch-tree "composer dump-autoload"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment