Skip to content

Instantly share code, notes, and snippets.

@divinity76
Last active December 11, 2023 19:40
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 divinity76/ec2a492723f408de84f941305b1e2f7f to your computer and use it in GitHub Desktop.
Save divinity76/ec2a492723f408de84f941305b1e2f7f to your computer and use it in GitHub Desktop.
rsync dir indefinitely whenever it changes.. syncer
#!/usr/bin/env php
<?php
declare (strict_types = 1);
global $argc, $argv;
if ($argc < 3) {
echo ("Usage: {$argv[0]} 'FOLDER' rsync FOLDER foo@bar:server_folder arg1 arg2 arg3 etc\n");
exit(1);
}
/**
* returns a plain string array of path to all files in a directory, including subdirectories,
* but does not return directories themselves. (meaning if a directory is empty, it will not be included at all)
*
* @param string $dir
* @param bool $realpath
* @throws UnexpectedValueException if $dir is not readable/does not exists
* @return string[] files
*/
function get_file_list_recursively(string $dir, bool $realpath = false): array
{
if (!is_readable($dir)) {
throw new UnexpectedValueException("Directory is not readable: {$dir}");
}
if(!is_dir($dir)){
return $realpath ? array(realpath($dir)) : array($dir);
}
$files = array();
$files = [];
foreach ((new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS))) as $file) {
/** @var SplFileInfo $file */
if ($realpath) {
$files[] = $file->getRealPath();
} else {
$files[] = $file->getPathname();
}
}
return $files;
}
function hasDirChanged(string $dir): bool
{
static $old_scans = array();
$files = get_file_list_recursively($dir, true);
$files = array_filter($files, function ($file) {
return true;
$ext = pathinfo($file, PATHINFO_EXTENSION);
$basename = pathinfo($file, PATHINFO_BASENAME);
if ($basename === "html.html") {
return false;
}
return in_array(strtolower($ext), array(
"php",
"js",
"css",
"html",
"htm",
//"txt",
), true); //
});
$files = array_values($files);
$scan = array();
foreach ($files as $file) {
// fnv164 is a very fast non-crypto hash
$hash = hash_file("fnv164", $file, true);
$scan[$file] = $hash;
}
if (isset($old_scans[$dir]) && $old_scans[$dir] === $scan) {
return false;
}
$old_scans[$dir] = $scan;
return true;
}
$single_instance = fopen(__FILE__, "rb");
if (!flock($single_instance, LOCK_EX | LOCK_NB)) {
fwrite(STDERR, "Another instance is already running.\n");
exit(1);
}
$scan_dir = $argv[1];
$rsync_command = '';
for ($i = 2; $i < $argc; ++$i) {
$rsync_command .= escapeshellarg($argv[$i]) . ' ';
}
echo "scan_dir: {$scan_dir} rsync_command: {$rsync_command}\n";
$sleep_time = 5;
echo "sleep time: {$sleep_time}\n";
for (;;) {
sleep($sleep_time);
if (!hasDirChanged($scan_dir)) {
continue;
}
echo "syncing!";
if (0) {
$cmd = implode(" ", array(
"rsync",
escapeshellarg(__DIR__),
escapeshellarg("solomeme") . "@" . escapeshellarg("solomeme.ratma.net") . ":" . escapeshellarg("/home/solomeme/websites/solomeme.ratma.net/www"),
"-aPz", // fsck it
"--exclude '*.sqlite3'",
"--exclude '*.txt'",
"--exclude '*.json'",
"--exclude 'html.html'",
));
} else {
$cmd = $rsync_command;
}
passthru($cmd, $ret);
if ($ret !== 0) {
echo "rsync failed with code {$ret}\n";
continue;
}
echo "SYNCED!\n";
}
//
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment