(Adding tomboy-list back to cc)
On Sat, May 2, 2009 at 6:13 PM, Michael Fletcher
<
m.fletcher@...> wrote:
>> Okay, then is it alright to filter on *.note and *.note.tmp?
>> Technically, Tomboy should work fine with notes that have non-GUID
>> names, so I'd like to get rid of the "if (note_id.Length != 36)" check
>> and replace it with a file extension check.
> This code was meant to make sure the note was actually a note (instead
> of say a manifest.xml file).
>
> I think everything will still work with a "*.note" filter. The code
> considers renaming to the file "a change" so it should see the note
> change.
>
> In an earlier conversation I had said that I was checking all files
> (*) so I could recognize the write,delete,rename pattern. This wasn't
> necessary. Seeing the rename event is sufficient to detect the
> change.
Okay, I made some minor changes in git, and I have a bigger patch
attached to this email that I intend to push, but thought it might be
useful to have you review it first if you have time. The main changes
are:
* A lot of try/catching and error-checking to catch bad note file
edits (needs more testing)
* Add/Delete notes using proper Tomboy API
* Use LoadForeignNoteXml to update more than just note title and content
* Save DateTimes for Note.Saved events, use them to ignore file
changes that happen within 3 seconds of such an event. I didn't do
this with Note deletion events because they error out pretty
gracefully already.
* Prefix all log statements with "NoteDirectoryWatcher: "
This will be part of Monday's release, so if you have time to review
that would rock.
Thanks,
Sandy
[0001-Update-NoteDirectoryWatcher-to-load-note-data-more-a.patch]
From e9e9a72a80a3495010e8fa11823ef0320dea6da1 Mon Sep 17 00:00:00 2001
From: Sandy Armstrong <sanfordarmstrong@...>
Date: Sat, 2 May 2009 20:28:09 -0700
Subject: [PATCH] Update NoteDirectoryWatcher to load note data more accurately and to be aware of Tomboy-generated file events.
---
.../NoteDirectoryWatcherApplicationAddin.cs | 123 ++++++++++++++------
1 files changed, 88 insertions(+), 35 deletions(-)
diff --git a/Tomboy/Addins/NoteDirectoryWatcher/NoteDirectoryWatcherApplicationAddin.cs b/Tomboy/Addins/NoteDirectoryWatcher/NoteDirectoryWatcherApplicationAddin.cs
index 157328b..7802a61 100644
--- a/Tomboy/Addins/NoteDirectoryWatcher/NoteDirectoryWatcherApplicationAddin.cs
+++ b/Tomboy/Addins/NoteDirectoryWatcher/NoteDirectoryWatcherApplicationAddin.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Text.RegularExpressions;
using Tomboy;
@@ -16,20 +17,24 @@ namespace Tomboy.NoteDirectoryWatcher
public class NoteDirectoryWatcherApplicationAddin : ApplicationAddin
{
+ // TODO: Use environment variable here?
private static bool VERBOSE_LOGGING = false;
private FileSystemWatcher file_system_watcher;
private bool initialized;
private Dictionary<string, NoteFileChangeRecord> file_change_records;
+ private Dictionary<string, DateTime> note_save_times;
public override void Initialize ()
{
string note_path = Tomboy.DefaultNoteManager.NoteDirectoryPath;
+ Tomboy.DefaultNoteManager.NoteSaved += OnNoteSaved;
file_change_records = new Dictionary<string, NoteFileChangeRecord> ();
+ note_save_times = new Dictionary<string, DateTime> ();
- file_system_watcher = new FileSystemWatcher (note_path);
+ file_system_watcher = new FileSystemWatcher (note_path, "*.note");
file_system_watcher.Changed += HandleFileSystemChangeEvent;
file_system_watcher.Deleted += HandleFileSystemChangeEvent;
@@ -55,6 +60,11 @@ namespace Tomboy.NoteDirectoryWatcher
get { return initialized; }
}
+ private void OnNoteSaved (Note note)
+ {
+ note_save_times [note.Id] = DateTime.Now;
+ }
+
private void HandleFileSystemErrorEvent (Object sender, ErrorEventArgs arg)
{
// TODO Rescan the local notes in case some of them have changed.
@@ -65,15 +75,7 @@ namespace Tomboy.NoteDirectoryWatcher
string note_id = GetId (arg.FullPath);
if (VERBOSE_LOGGING)
- Logger.Debug ("{0} has {1} (note_id={2})", arg.FullPath, arg.ChangeType, note_id);
-
- // If the note_id is long 36 characters then the file probably wasn't a note.
- if (note_id.Length != 36) {
- if (VERBOSE_LOGGING)
- Logger.Debug ("Ignoring change to {0}", arg.FullPath);
-
- return;
- }
+ Logger.Debug ("NoteDirectoryWatcher: {0} has {1} (note_id={2})", arg.FullPath, arg.ChangeType, note_id);
// Record that the file has been added/changed/deleted. Adds/changes trump
// deletes. Record the date.
@@ -100,8 +102,10 @@ namespace Tomboy.NoteDirectoryWatcher
if (!record.changed)
record.deleted = true;
} else {
- String message = "Unexpected WatcherChangeType " + arg.ChangeType;
+ string message = "NoteDirectoryWatcher: Unexpected WatcherChangeType " + arg.ChangeType;
Logger.Error (message);
+ // TODO: Why are we throwing an exception here?
+ // What are the repercussions of this?
throw new Exception (message);
}
@@ -118,7 +122,17 @@ namespace Tomboy.NoteDirectoryWatcher
foreach (KeyValuePair<string, NoteFileChangeRecord> pair in file_change_records) {
if (VERBOSE_LOGGING)
- Logger.Debug ("Handling (timeout) {0}", pair.Key);
+ Logger.Debug ("NoteDirectoryWatcher: Handling (timeout) {0}", pair.Key);
+
+ // Check that Note.Saved event didn't occur within 3 seconds of last write
+ if (note_save_times.ContainsKey (pair.Key) &&
+ Math.Abs (note_save_times [pair.Key].Ticks - pair.Value.last_change.Ticks) <= 3000*10000) {
+ if (VERBOSE_LOGGING)
+ Logger.Debug ("NoteDirectoryWatcher: Ignoring (timeout) because it was probably a Tomboy write");
+ keysToRemove.Add (pair.Key);
+ continue;
+ }
+ // TODO: Take some actions to clear note_save_times? Not a large structure...
if (DateTime.Now > pair.Value.last_change.Add (new TimeSpan (4000)) ) {
if (pair.Value.deleted)
@@ -139,48 +153,87 @@ namespace Tomboy.NoteDirectoryWatcher
private static void DeleteNote (string note_id)
{
- Logger.Debug ("Deleting {0} because file deleted.", note_id);
+ Logger.Debug ("NoteDirectoryWatcher: Deleting {0} because file deleted.", note_id);
string note_uri = MakeUri (note_id);
Note note_to_delete = Tomboy.DefaultNoteManager.FindByUri (note_uri);
-
- Tomboy.DefaultNoteManager.Notes.Remove (note_to_delete);
-
- note_to_delete.Delete ();
+ if (note_to_delete != null)
+ Tomboy.DefaultNoteManager.Delete (note_to_delete);
+ else if (VERBOSE_LOGGING)
+ Logger.Debug ("NoteDirectoryWatcher: Did not delete {0} because note not found.", note_id);
}
- private static void AddOrUpdateNote (string note_id)
+ private void AddOrUpdateNote (string note_id)
{
string note_path = Tomboy.DefaultNoteManager.NoteDirectoryPath +
Path.DirectorySeparatorChar + note_id + ".note";
+ if (!File.Exists (note_path)) {
+ // TODO: Any need to handle a deletion here?
+ if (VERBOSE_LOGGING)
+ Logger.Debug ("NoteDirectoryWatcher: Not processing update of {0} because file does not exist.", note_path);
+ return;
+ }
+
+ string noteXml = null;
+ try {
+ using (StreamReader reader = new StreamReader (note_path)) {
+ noteXml = reader.ReadToEnd ();
+ }
+ } catch (Exception e) {
+ Logger.Error ("NoteDirectoryWatcher: Update aborted, error reading {0}: {1}", note_path, e);
+ }
+
+ if (string.IsNullOrEmpty (noteXml)) {
+ if (VERBOSE_LOGGING)
+ Logger.Debug ("NoteDirectoryWatcher: Update aborted, {0} had no contents.", note_path);
+ return;
+ }
string note_uri = MakeUri (note_id);
Note note = Tomboy.DefaultNoteManager.FindByUri (note_uri);
+ bool is_new_note = false;
+
if (note == null) {
- Logger.Debug ("Adding {0} because file changed.", note_id);
- Note new_note = Note.Load (note_path, Tomboy.DefaultNoteManager);
- Tomboy.DefaultNoteManager.Notes.Add (new_note);
- } else {
- NoteData data = NoteArchiver.Instance.ReadFile (note_path, note_uri);
-
- // Only record changes if the note actually changes. This prevents the Addin from
- // noticing changes from Tomboy itself.
- if (data.Text == note.XmlContent)
- {
- if (VERBOSE_LOGGING)
- Logger.Debug ("Ignoring {0} because contents identical", note_id);
- } else {
- Logger.Debug ("Updating {0} because file changed.", note_id);
- note.XmlContent = data.Text;
- note.Title = data.Title;
+ is_new_note = true;
+ Logger.Debug ("NoteDirectoryWatcher: Adding {0} because file changed.", note_id);
+
+ string title = null;
+ const string title_group_name = "title";
+ Match match = Regex.Match (noteXml, "<title>(?<" + title_group_name + ">[^<]+)</title>");
+ if (match.Success)
+ title = match.Groups [title_group_name].Value;
+ else {
+ Logger.Error ("NoteDirectoryWatcher: Error reading note title from {0}", note_path);
+ return;
}
+
+ try {
+ note = Tomboy.DefaultNoteManager.CreateWithGuid (title, note_id);
+ if (note == null) {
+ Logger.Error ("NoteDirectoryWatcher: Unknown error creating note from {0}", note_path);
+ return;
+ }
+ } catch (Exception e) {
+ Logger.Error ("NoteDirectoryWatcher: Error creating note from {0}: {1}", note_path, e);
+ return;
+ }
+ }
+
+ if (is_new_note)
+ Logger.Debug ("NoteDirectoryWatcher: Updating {0} because file changed.", note_id);
+ try {
+ note.LoadForeignNoteXml (noteXml, ChangeType.ContentChanged);
+ } catch (Exception e) {
+ Logger.Error ("NoteDirectoryWatcher: Update aborted, error parsing {0}: {1}", note_path, e);
+ if (is_new_note)
+ Tomboy.DefaultNoteManager.Delete (note);
}
}
- private static String MakeUri (string note_id)
+ private static string MakeUri (string note_id)
{
return "note://tomboy/" + note_id;
}
--
1.6.2.4
_______________________________________________
Tomboy-list mailing list
Tomboy-list@...
http://lists.beatniksoftware.com/listinfo.cgi/tomboy-list-beatniksoftware.com