From ca22672842f87fb04299215dbf4b8c1289a60c0d Mon Sep 17 00:00:00 2001 From: Hylke Bons Date: Sun, 8 Jul 2012 23:53:44 +0200 Subject: [PATCH] Use only a single watcher to monitor the SparkleShare folder --- SparkleLib/Makefile.am | 1 + SparkleLib/SparkleRepoBase.cs | 29 +---------- SparkleLib/SparkleWatcher.cs | 75 ++++++++++++++------------- SparkleLib/SparkleWatcherFactory.cs | 35 +++++++++---- SparkleShare/Mac/SparkleController.cs | 39 +++----------- SparkleShare/Mac/SparkleMacWatcher.cs | 21 ++------ SparkleShare/SparkleControllerBase.cs | 6 +++ 7 files changed, 84 insertions(+), 122 deletions(-) diff --git a/SparkleLib/Makefile.am b/SparkleLib/Makefile.am index 1a6d1b8b..ae45bf91 100755 --- a/SparkleLib/Makefile.am +++ b/SparkleLib/Makefile.am @@ -16,6 +16,7 @@ SOURCES = \ SparkleRepoBase.cs \ SparkleUser.cs \ SparkleWatcher.cs \ + SparkleWatcherFactory.cs \ SparkleWrappers.cs diff --git a/SparkleLib/SparkleRepoBase.cs b/SparkleLib/SparkleRepoBase.cs index 42c5ac50..932f0cbc 100755 --- a/SparkleLib/SparkleRepoBase.cs +++ b/SparkleLib/SparkleRepoBase.cs @@ -152,7 +152,7 @@ namespace SparkleLib { this.identifier = Identifier; ChangeSets = GetChangeSets (); - this.watcher = CreateWatcher (); + this.watcher = SparkleWatcherFactory.CreateWatcher (this); new Thread ( new ThreadStart (delegate { @@ -201,11 +201,6 @@ namespace SparkleLib { public void OnFileActivity (FileSystemEventArgs args) { - // Check the watcher for the occasions where this - // method is called directly - if (!this.watcher.EnableRaisingEvents || IsBuffering) - return; - lock (this.change_lock) { this.remote_timer.Stop (); @@ -220,7 +215,6 @@ namespace SparkleLib { if (!IsBuffering && HasLocalChanges) { IsBuffering = true; - this.watcher.Disable (); SparkleHelpers.DebugInfo ("Local", Name + " | Activity detected, waiting for it to settle..."); @@ -244,10 +238,8 @@ namespace SparkleLib { SparkleHelpers.DebugInfo ("Local", Name + " | Activity has settled"); IsBuffering = false; - this.watcher.Disable (); while (HasLocalChanges) SyncUpBase (); - this.watcher.Enable (); } else { Thread.Sleep (500); @@ -271,7 +263,6 @@ namespace SparkleLib { private void SyncUpBase () { try { - this.watcher.Disable (); this.remote_timer.Stop (); SparkleHelpers.DebugInfo ("SyncUp", Name + " | Initiated"); @@ -294,7 +285,6 @@ namespace SparkleLib { HasUnsyncedChanges = true; SyncDownBase (); - this.watcher.Disable (); if (ServerOnline && SyncUp ()) { HasUnsyncedChanges = false; @@ -314,7 +304,6 @@ namespace SparkleLib { } finally { this.remote_timer.Start (); - this.watcher.Enable (); ProgressPercentage = 0.0; ProgressSpeed = ""; @@ -326,7 +315,6 @@ namespace SparkleLib { { SparkleHelpers.DebugInfo ("SyncDown", Name + " | Initiated"); this.remote_timer.Stop (); - this.watcher.Disable (); if (SyncStatusChanged != null) SyncStatusChanged (SyncStatus.SyncDown); @@ -380,19 +368,6 @@ namespace SparkleLib { SyncStatusChanged (SyncStatus.Idle); this.remote_timer.Start (); - this.watcher.Enable (); - } - - - private SparkleWatcher CreateWatcher () - { - SparkleWatcher watcher = new SparkleWatcher (LocalPath); - - watcher.ChangeEvent += delegate (FileSystemEventArgs args) { - OnFileActivity (args); - }; - - return watcher; } @@ -456,7 +431,7 @@ namespace SparkleLib { !announcement.Message.Equals (CurrentRevision)) { while (this.is_syncing) - System.Threading.Thread.Sleep (100); + Thread.Sleep (100); SparkleHelpers.DebugInfo ("Listener", "Syncing due to announcement"); SyncDownBase (); diff --git a/SparkleLib/SparkleWatcher.cs b/SparkleLib/SparkleWatcher.cs index 4b6d75de..2f0caaa5 100755 --- a/SparkleLib/SparkleWatcher.cs +++ b/SparkleLib/SparkleWatcher.cs @@ -16,57 +16,60 @@ using System; -using System.IO; +using System.Collections.Generic; +using System.Threading; + +using IO = System.IO; namespace SparkleLib { - public class SparkleWatcher : FileSystemWatcher { + public class SparkleWatcher : IO.FileSystemWatcher { - public delegate void ChangeEventEventHandler (FileSystemEventArgs args); - public event ChangeEventEventHandler ChangeEvent; - - private Object thread_lock = new Object (); + public List ReposToNotify = new List (); - public SparkleWatcher (string path) : base (path) + public SparkleWatcher (SparkleRepoBase repo) { + ReposToNotify.Add (repo); + + Changed += Notify; + Created += Notify; + Deleted += Notify; + Renamed += Notify; + + Filter = "*"; + Path = IO.Path.GetDirectoryName (repo.LocalPath); + IncludeSubdirectories = true; EnableRaisingEvents = true; - Filter = "*"; - - Changed += delegate (object o, FileSystemEventArgs args) { - if (ChangeEvent != null) - ChangeEvent (args); - }; - - Created += delegate (object o, FileSystemEventArgs args) { - if (ChangeEvent != null) - ChangeEvent (args); - }; - - Deleted += delegate (object o, FileSystemEventArgs args) { - if (ChangeEvent != null) - ChangeEvent (args); - }; - - Renamed += delegate (object o, RenamedEventArgs args) { - if (ChangeEvent != null) - ChangeEvent (args); - }; } - public void Enable () + public void Notify (object sender, IO.FileSystemEventArgs args) { - lock (this.thread_lock) - EnableRaisingEvents = true; - } + char separator = IO.Path.DirectorySeparatorChar; + string relative_path = args.FullPath.Substring (Path.Length); + relative_path = relative_path.Trim (new char [] {' ', separator}); + // Ignore changes that happened in the parent path + if (!relative_path.Contains (separator.ToString ())) + return; - public void Disable () - { - lock (this.thread_lock) - EnableRaisingEvents = false; + string repo_name = relative_path.Substring (0, relative_path.IndexOf (separator)); + + foreach (SparkleRepoBase repo in ReposToNotify) { + if (repo.Name.Equals (repo_name) && !repo.IsBuffering && + (repo.Status != SyncStatus.SyncUp && repo.Status != SyncStatus.SyncDown)) { + + Thread thread = new Thread ( + new ThreadStart (delegate { + repo.OnFileActivity (args); + }) + ); + + thread.Start (); + } + } } } } diff --git a/SparkleLib/SparkleWatcherFactory.cs b/SparkleLib/SparkleWatcherFactory.cs index 94606363..61b9f29d 100644 --- a/SparkleLib/SparkleWatcherFactory.cs +++ b/SparkleLib/SparkleWatcherFactory.cs @@ -21,30 +21,43 @@ using System.IO; namespace SparkleLib { - public static class SparkleListenerFactory { + public static class SparkleWatcherFactory { private static List watchers = new List (); - public static SparkleWatcher CreateWatcher (string path_to_watch) + public static SparkleWatcher CreateWatcher (SparkleRepoBase repo_to_watch) { - path_to_watch = Path.GetDirectoryName (path_to_watch); - foreach (SparkleWatcher watcher in watchers) { - if (watcher.Path.Equals (path_to_watch)) { - SparkleHelpers.DebugInfo ("WatcherFactory", - "Refered to existing watcher for " + path_to_watch); + foreach (SparkleRepoBase repo in watcher.ReposToNotify) { + string path_to_watch = Path.GetDirectoryName (repo_to_watch.LocalPath); - return watcher; + if (watcher.Path.Equals (path_to_watch)) { + watcher.ReposToNotify.Add (repo_to_watch); + SparkleHelpers.DebugInfo ("WatcherFactory", "Refered to existing watcher for " + path_to_watch); + + return watcher; + } } } - watchers.Add (new SparkleWatcher (path_to_watch)); + SparkleWatcher new_watcher = new SparkleWatcher (repo_to_watch); + watchers.Add (new_watcher); - SparkleHelpers.DebugInfo ("WatcherFactory", - "Issued new watcher for " + path_to_watch); + SparkleHelpers.DebugInfo ("WatcherFactory", "Issued new watcher for " + repo_to_watch.Name); return watchers [watchers.Count - 1]; } + + + public static void TriggerWatcherManually (FileSystemEventArgs args) + { + foreach (SparkleWatcher watcher in watchers) { + if (args.FullPath.StartsWith (watcher.Path)) { + watcher.Notify (null, args); + return; + } + } + } } } diff --git a/SparkleShare/Mac/SparkleController.cs b/SparkleShare/Mac/SparkleController.cs index 2a3ffc79..ad8a5bf4 100755 --- a/SparkleShare/Mac/SparkleController.cs +++ b/SparkleShare/Mac/SparkleController.cs @@ -57,12 +57,10 @@ namespace SparkleShare { // Let's use the bundled git first SparkleLib.Git.SparkleGit.GitPath = - Path.Combine (NSBundle.MainBundle.ResourcePath, - "git", "libexec", "git-core", "git"); + Path.Combine (NSBundle.MainBundle.ResourcePath, "git", "libexec", "git-core", "git"); SparkleLib.Git.SparkleGit.ExecPath = - Path.Combine (NSBundle.MainBundle.ResourcePath, - "git", "libexec", "git-core"); + Path.Combine (NSBundle.MainBundle.ResourcePath, "git", "libexec", "git-core"); } @@ -70,36 +68,13 @@ namespace SparkleShare { { base.Initialize (); - this.watcher.Changed += delegate (object sender, SparkleMacWatcherEventArgs args) { - string path = args.Path; + this.watcher.Changed += delegate (string path) { + string full_path = Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, path + "/something"); - // Don't even bother with paths in .git/ - if (path.Contains (".git")) - return; + FileSystemEventArgs event_args = new FileSystemEventArgs (WatcherChangeTypes.Changed, + Path.GetDirectoryName (full_path), Path.GetFileName (full_path)); - string repo_name; - - if (path.Contains ("/")) - repo_name = path.Substring (0, path.IndexOf ("/")); - else - repo_name = path; - - // Ignore changes in the root of each subfolder, these - // are already handled by the repository - if (Path.GetFileNameWithoutExtension (path).Equals (repo_name)) - return; - - repo_name = repo_name.Trim ("/".ToCharArray ()); - FileSystemEventArgs fse_args = new FileSystemEventArgs ( - WatcherChangeTypes.Changed, - Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, path), - Path.GetFileName (path) - ); - - foreach (SparkleRepoBase repo in Repositories) { - if (repo.Name.Equals (repo_name)) - repo.OnFileActivity (fse_args); - } + SparkleWatcherFactory.TriggerWatcherManually (event_args); }; } diff --git a/SparkleShare/Mac/SparkleMacWatcher.cs b/SparkleShare/Mac/SparkleMacWatcher.cs index 28f8c089..8f338c8f 100755 --- a/SparkleShare/Mac/SparkleMacWatcher.cs +++ b/SparkleShare/Mac/SparkleMacWatcher.cs @@ -53,25 +53,14 @@ using MonoMac.Foundation; namespace SparkleShare { - [Serializable] - public sealed class SparkleMacWatcherEventArgs : EventArgs { + public sealed class SparkleMacWatcher : IDisposable { + + public delegate void ChangedEventHandler (string path); + public event ChangedEventHandler Changed; public string Path { get; private set; } - public SparkleMacWatcherEventArgs (string path) - { - Path = path; - } - } - - - public sealed class SparkleMacWatcher : IDisposable - { - public event EventHandler Changed; - public string Path { get; private set; } - - [Flags] [Serializable] private enum FSEventStreamCreateFlags : uint @@ -186,7 +175,7 @@ namespace SparkleShare { string path = paths [0]; path = path.Substring (Path.Length); path = path.Trim ("/".ToCharArray ()); - handler (this, new SparkleMacWatcherEventArgs (path)); + handler (path); } GC.KeepAlive (this); diff --git a/SparkleShare/SparkleControllerBase.cs b/SparkleShare/SparkleControllerBase.cs index 19985933..a7f27f87 100644 --- a/SparkleShare/SparkleControllerBase.cs +++ b/SparkleShare/SparkleControllerBase.cs @@ -284,6 +284,12 @@ namespace SparkleShare { return; } else { + if (Directory.Exists (args.FullPath) && + args.ChangeType == WatcherChangeTypes.Created) { + + return; + } + CheckRepositories (); } }