WebFreak001 / FSWatch

A cross-platform folder & file watching library using win32, inotify or std.file
33 stars 8 forks source link

Can it be used to check for file changes across runs? #23

Closed aminya closed 3 years ago

aminya commented 3 years ago

Is it possible to use the comparing functionality of fswatch to get a unique hash and store it somewhere for later comparison? I am trying to see if https://github.com/dlang/dub/issues/2163 can be fixed by running a simple check before rebuilding.

WebFreak001 commented 3 years ago

no, this library is only for watching for live changes while the program is running.

For your use-case of seeing if one or more files have changed across program runs you could for example use the lastModified time of all the files and the filenames and just throw them all into some hashing algorithm, (like std.digest.sha:SHA1) the hash can then be used for comparison to see if anything has changed, been removed or added.

aminya commented 3 years ago

I made an implementation of what I need. Should I add it as a PR to this library?

import std.file : DirEntry, write, read, tempDir, exists, SpanMode, dirEntries;
import std.path : buildPath, extension, baseName;
import std.digest: hexDigest;
import std.digest.crc: CRC32;

/** Check if a folder has changed
  Params:
    rootDir = the directory to check
    pattern = the pattern to check like "*.{d,di}"
  Returns:
    a boolean showing if the folder has changed
*/
bool folderHasChanged(string rootDir, string pattern) @trusted
{
  const cacheName = buildPath(tempDir(), hexDigest!CRC32(pattern ~ rootDir.baseName()));
  const newCache = getUniqueHash(rootDir, pattern);
  if (!cacheName.exists())
  {
    write(cacheName, newCache);
    return true;
  }
  const changed = newCache != cast(ulong[]) read(cacheName);
  if (changed) {
    write(cacheName, newCache);
  }
  return changed;
}

/** Get a unique cache for a directory
  Params:
    rootDir = the directory to check
    pattern = the pattern to check like "*.{d,di}"
  Returns:
    a buffer of `ulong[]`
*/
ulong[] getUniqueHash(string rootDir, string pattern) @trusted
{
  ulong[] buffer;
  foreach (directoryEntry; dirEntries(rootDir, pattern, SpanMode.breadth))
  {
    buffer ~= getUniqueHash(directoryEntry);
  }
  return buffer;
}

/// Get a unique hash for a DirEntry
/// https://github.com/WebFreak001/FSWatch/blob/1925700c64d9a26fbb2a6231b2cf94dc343800a4/source/fswatch.d#L38
ulong getUniqueHash(DirEntry entry) @trusted
{
  version (Windows)
    return entry.timeLastModified.stdTime ^ cast(ulong) entry.attributes;
  else version (Posix)
    return entry.statBuf.st_ino | (cast(ulong) entry.statBuf.st_dev << 32UL);
  else
    return (entry.timeLastModified.stdTime ^ (
        cast(ulong) entry.attributes << 32UL) ^ entry.linkAttributes) * entry.size;
}
WebFreak001 commented 3 years ago

no I think this is out of scope for this library

aminya commented 3 years ago

OK. Thanks. I might put on dub in case someone needs it.