diff --git a/SparkleLib/SparkleListener.cs b/SparkleLib/SparkleListener.cs index d0cfcad1..3b48a344 100644 --- a/SparkleLib/SparkleListener.cs +++ b/SparkleLib/SparkleListener.cs @@ -26,11 +26,11 @@ namespace SparkleLib { { public IrcClient Client; - public Thread Thread; - public string Server; - public string Channel; - public string Nick; - public int Port; + private Thread Thread; + public readonly string Server; + public readonly string Channel; + public readonly string Nick; + public SparkleListener (string server, string channel, string nick) { @@ -38,7 +38,6 @@ namespace SparkleLib { Server = server; Channel = channel; Nick = nick.Replace ("@", "_at_").Replace (".", "_dot_"); - Port = 6667; if (Nick.Length > 9) Nick = Nick.Substring (0, 9); @@ -49,15 +48,14 @@ namespace SparkleLib { Client = new IrcClient (); - Client.AutoRejoin = true; - Client.AutoRetry = true; - Client.AutoRelogin = true; +// PingTimeout = 90; +// SocketSendTimeout = 90; } // Starts a new thread and listens to the channel - public void Listen () + public void ListenForChanges () { Thread = new Thread ( @@ -66,7 +64,7 @@ namespace SparkleLib { try { // Connect to the server - Client.Connect (new string [] {Server}, Port); + Client.Connect (new string [] {Server}, 6667); // Login to the server Client.Login (Nick, Nick); @@ -78,7 +76,7 @@ namespace SparkleLib { Client.Disconnect (); - } catch ( Meebey.SmartIrc4net.ConnectionException e) { + } catch (Meebey.SmartIrc4net.ConnectionException e) { Console.WriteLine ("Could not connect: " + e.Message); @@ -91,6 +89,15 @@ namespace SparkleLib { } + + public void Dispose () + { + + Thread.Abort (); + Thread.Join (); + + } + } } diff --git a/SparkleLib/SparkleRepo.cs b/SparkleLib/SparkleRepo.cs index 2b8afdb2..01a747df 100644 --- a/SparkleLib/SparkleRepo.cs +++ b/SparkleLib/SparkleRepo.cs @@ -37,31 +37,196 @@ namespace SparkleLib { private int FetchRequests; private SparkleListener Listener; - public string Name; - public string RemoteName; - public string Domain; - public string Description; - public string LocalPath; - public string RemoteOriginUrl; - public string CurrentHash; - public string UserEmail; - public string UserName; - public bool IsSyncing; - public bool IsBuffering; - public bool IsPolling; - public bool IsFetching; - public bool HasUnsyncedChanges; + /// + /// The folder name the repository resides in locally + /// + public readonly string Name; + /// + /// The folder name the repository resides in remotely + /// + public readonly string RemoteName; + + /// + /// The domain the remote repository is on + /// + public readonly string Domain; + + /// + /// The repository's description + /// + public readonly string Description; + + /// + /// The path where the repository resides locally + /// + public readonly string LocalPath; + + /// + /// The raw url used to sync with. + /// + public readonly string RemoteOriginUrl; + + private string _CurrentHash; + private string _UserEmail; + private string _UserName; + private bool _IsSyncing; + private bool _IsBuffering; + private bool _IsPolling; + private bool _IsFetching; + private bool _IsPushing; + private bool _HasUnsyncedChanges; + + + /// + /// The hash of the last commit done in the repository + /// + public string CurrentHash { + get { + return _CurrentHash; + } + } + + /// + /// The name of the user + /// + public string UserName { + get { + return _UserName; + } + set { + SetUserName (value); + } + } + + + /// + /// The name of the user + /// + public string UserEmail { + get { + return _UserEmail; + } + set { + SetUserEmail (value); + } + } + + + /// + /// Indicates whether the repository is currently waiting for local changes to settle + /// + public bool IsBuffering { + get { + return _IsBuffering; + } + } + + + /// + /// Indicates whether the repository is currently pushing changes + /// + public bool IsPushing { + get { + return _IsPushing; + } + } + + + /// + /// Indicates whether the repository has fallen back to polling the remote repository, + /// instead of receiving instant notifications + /// + public bool IsPolling { + get { + return _IsPolling; + } + } + + + /// + /// Indicates whether the repository is currently fetching and/or pushing changes + /// + public bool IsSyncing { + get { + return _IsSyncing; + } + } + + + /// + /// Indicates whether the repository is currently fetching remote changes + /// + public bool IsFetching { + get { + return _IsFetching; + } + } + + + /// + /// Indicates whether the repository has local changes that aren't pushed remotely yet + /// + public bool HasUnsyncedChanges { + get { + return _HasUnsyncedChanges; + } + } + + /// + /// Raised when local files have been added to the repository's staging area + /// public delegate void AddedEventHandler (object o, SparkleEventArgs args); + + /// + /// Raised when local files have been added to the repository's index + /// public delegate void CommitedEventHandler (object o, SparkleEventArgs args); + + /// + /// Raised when the repository has started pushing changes + /// public delegate void PushingStartedEventHandler (object o, SparkleEventArgs args); + + /// + /// Raised when the repository has finished pushing changes + /// public delegate void PushingFinishedEventHandler (object o, SparkleEventArgs args); + + /// + /// Raised when pushing changes has failed + /// public delegate void PushingFailedEventHandler (object o, SparkleEventArgs args); + + /// + /// Raised when when the repository has started fetching remote changes + /// public delegate void FetchingStartedEventHandler (object o, SparkleEventArgs args); + + /// + /// Raised when when the repository has finished fetching remote changes + /// public delegate void FetchingFinishedEventHandler (object o, SparkleEventArgs args); + + /// + /// Raised when the repository has received one or multiple new remote commits + /// public delegate void NewCommitEventHandler (object o, NewCommitArgs args); + + /// + /// Raised when the newly fetched commits are conflicting with local changes + /// public delegate void ConflictDetectedEventHandler (object o, SparkleEventArgs args); + + /// + /// Raised when local files have changed in the repository's folder + /// public delegate void ChangesDetectedEventHandler (object o, SparkleEventArgs args); + + /// + /// Raised when there were changes made to local files, but the net result after changes have settled + /// ended up the same as before the changes were made. + /// public delegate void CommitEndedUpEmptyEventHandler (object o, SparkleEventArgs args); public event AddedEventHandler Added; @@ -80,9 +245,6 @@ namespace SparkleLib { public SparkleRepo (string path) { - LocalPath = path; - Name = Path.GetFileName (LocalPath); - Process = new Process () { EnableRaisingEvents = true }; @@ -92,20 +254,24 @@ namespace SparkleLib { Process.StartInfo.UseShellExecute = false; Process.StartInfo.WorkingDirectory = LocalPath; - UserName = GetUserName (); - UserEmail = GetUserEmail (); - RemoteOriginUrl = GetRemoteOriginUrl (); - CurrentHash = GetCurrentHash (); - Domain = GetDomain (RemoteOriginUrl); - RemoteName = Path.GetFileNameWithoutExtension (RemoteOriginUrl); - Description = GetDescription (); - HasUnsyncedChanges = false; - IsSyncing = false; - IsBuffering = false; - IsPolling = true; - IsFetching = false; + LocalPath = path; + Name = Path.GetFileName (LocalPath); + RemoteName = Path.GetFileNameWithoutExtension (RemoteOriginUrl); + RemoteOriginUrl = GetRemoteOriginUrl (); + Domain = GetDomain (RemoteOriginUrl); + Description = GetDescription (); - if (CurrentHash == null) + _UserName = GetUserName (); + _UserEmail = GetUserEmail (); + _CurrentHash = GetCurrentHash (); + _HasUnsyncedChanges = false; + _IsSyncing = false; + _IsBuffering = false; + _IsPolling = true; + _IsFetching = false; + _IsPushing = false; + + if (_CurrentHash == null) CreateInitialCommit (); HasChanged = false; @@ -134,13 +300,13 @@ namespace SparkleLib { CheckForRemoteChanges (); - if (HasUnsyncedChanges) + if (_HasUnsyncedChanges) Push (); }; // Listen to the irc channel on the server - Listener = new SparkleListener (Domain, "#" + RemoteName, UserEmail); + Listener = new SparkleListener (Domain, "#" + RemoteName, _UserEmail); // Stop polling when the connection to the irc channel is succesful Listener.Client.OnConnected += delegate { @@ -148,7 +314,7 @@ namespace SparkleLib { SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Connected. Now listening..."); RemoteTimer.Stop (); - IsPolling = false; + _IsPolling = false; }; @@ -158,7 +324,7 @@ namespace SparkleLib { SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Lost connection. Falling back to polling..."); RemoteTimer.Start (); - IsPolling = true; + _IsPolling = true; }; @@ -168,11 +334,11 @@ namespace SparkleLib { SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Was notified of a remote change."); - if (!args.Data.Message.Equals (CurrentHash)) { //TODO: args.Data.NewTopic + if (!args.Data.Message.Equals (_CurrentHash)) { //TODO: args.Data.NewTopic FetchRequests++; - if (!IsFetching) { + if (!_IsFetching) { while (FetchRequests > 0) { @@ -188,14 +354,14 @@ namespace SparkleLib { } else { SparkleHelpers.DebugInfo ("Irc", - "[" + Name + "] False alarm, already up to date. (" + CurrentHash + ")"); + "[" + Name + "] False alarm, already up to date. (" + _CurrentHash + ")"); } }; // Start listening - Listener.Listen (); + Listener.ListenForChanges (); // Keep a timer that checks if there are changes and @@ -209,7 +375,7 @@ namespace SparkleLib { }; - if (IsPolling) + if (_IsPolling) RemoteTimer.Start (); LocalTimer.Start (); @@ -220,8 +386,8 @@ namespace SparkleLib { // since SparkleShare was stopped AddCommitAndPush (); - if (CurrentHash == null) - CurrentHash = GetCurrentHash (); + if (_CurrentHash == null) + _CurrentHash = GetCurrentHash (); } @@ -249,7 +415,7 @@ namespace SparkleLib { string remote_hash = process.StandardOutput.ReadToEnd (); - if (!remote_hash.StartsWith (CurrentHash)) { + if (!remote_hash.StartsWith (_CurrentHash)) { SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Remote changes found."); Fetch (); @@ -278,7 +444,7 @@ namespace SparkleLib { SparkleHelpers.DebugInfo ("Local", "[" + Name + "] Changes have settled, adding files..."); - IsBuffering = false; + _IsBuffering = false; HasChanged = false; AddCommitAndPush (); @@ -300,7 +466,7 @@ namespace SparkleLib { if (!ShouldIgnore (fse_args.FullPath)) { - IsBuffering = true; + _IsBuffering = true; // Only fire the event if the timer has been stopped. // This prevents multiple events from being raised whilst "buffering". @@ -360,7 +526,7 @@ namespace SparkleLib { } finally { - if (IsPolling) + if (_IsPolling) RemoteTimer.Start (); LocalTimer.Start (); @@ -420,8 +586,8 @@ namespace SparkleLib { public void Fetch () { - IsSyncing = true; - IsFetching = true; + _IsSyncing = true; + _IsFetching = true; RemoteTimer.Stop (); @@ -453,16 +619,16 @@ namespace SparkleLib { args = new SparkleEventArgs ("FetchingFinished"); - IsSyncing = false; - IsFetching = false; + _IsSyncing = false; + _IsFetching = false; if (FetchingFinished != null) FetchingFinished (this, args); - if (IsPolling) + if (_IsPolling) RemoteTimer.Start (); - CurrentHash = GetCurrentHash (); + _CurrentHash = GetCurrentHash (); }; @@ -511,7 +677,7 @@ namespace SparkleLib { string timestamp = DateTime.Now.ToString ("H:mm d MMM yyyy"); - File.Move (problem_file_name, problem_file_name + " (" + UserName + ", " + timestamp + ")"); + File.Move (problem_file_name, problem_file_name + " (" + _UserName + ", " + timestamp + ")"); Process.StartInfo.Arguments = "checkout --theirs " + problem_file_name; Process.WaitForExit (); @@ -569,7 +735,8 @@ namespace SparkleLib { public void Push () { - IsSyncing = true; + _IsSyncing = true; + _IsPushing = true; SparkleEventArgs args = new SparkleEventArgs ("PushingStarted"); @@ -585,11 +752,14 @@ namespace SparkleLib { Process.Exited += delegate { + _IsSyncing = false; + _IsPushing = false; + if (Process.ExitCode != 0) { SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Pushing failed."); - HasUnsyncedChanges = true; + _HasUnsyncedChanges = true; args = new SparkleEventArgs ("PushingFailed"); @@ -602,28 +772,24 @@ namespace SparkleLib { args = new SparkleEventArgs ("PushingFinished"); - HasUnsyncedChanges = false; + _HasUnsyncedChanges = false; if (PushingFinished != null) PushingFinished (this, args); } - IsSyncing = false; - }; } - public void Stop () + public void Dispose () { RemoteTimer.Dispose (); LocalTimer.Dispose (); - - Listener.Thread.Abort (); - Listener.Thread.Join (); + Listener.Dispose (); } @@ -654,10 +820,10 @@ namespace SparkleLib { public string GetDomain (string url) { - if (RemoteOriginUrl.Equals ("")) + if (url.Equals ("")) return ""; - string domain = url.Substring (RemoteOriginUrl.IndexOf ("@") + 1); + string domain = url.Substring (url.IndexOf ("@") + 1); if (domain.IndexOf (":") > -1) domain = domain.Substring (0, domain.IndexOf (":")); @@ -749,8 +915,25 @@ namespace SparkleLib { } + // Gets the user's name, example: "User Name" + private void SetUserName (string user_name) + { + + Process process = new Process (); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.FileName = "git"; + process.StartInfo.WorkingDirectory = LocalPath; + process.StartInfo.Arguments = "config --set user.name \"" + user_name + "\""; + process.Start (); + + _UserName = user_name; + + } + + // Gets the user's email, example: "person@gnome.org" - public string GetUserEmail () + private string GetUserEmail () { string user_email; @@ -773,6 +956,23 @@ namespace SparkleLib { } + // Gets the user's name, example: "User Name" + private void SetUserEmail (string user_email) + { + + Process process = new Process (); + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.FileName = "git"; + process.StartInfo.WorkingDirectory = LocalPath; + process.StartInfo.Arguments = "config --set user.email \"" + user_email + "\""; + process.Start (); + + _UserEmail = user_email; + + } + + // Create a first commit in case the user has cloned // an empty repository private void CreateInitialCommit () diff --git a/SparkleShare/SparkleLog.cs b/SparkleShare/SparkleLog.cs index 5d761366..3adf28d1 100644 --- a/SparkleShare/SparkleLog.cs +++ b/SparkleShare/SparkleLog.cs @@ -113,10 +113,11 @@ namespace SparkleShare { } - HideAll (); + HideAll (); // TODO: destroy it } + public void UpdateEventLog (object o, EventArgs args) { diff --git a/SparkleShare/SparkleStatusIcon.cs b/SparkleShare/SparkleStatusIcon.cs index 5d72d03a..70c32aec 100644 --- a/SparkleShare/SparkleStatusIcon.cs +++ b/SparkleShare/SparkleStatusIcon.cs @@ -457,8 +457,7 @@ namespace SparkleShare { { foreach (SparkleRepo repo in SparkleUI.Repositories) - repo.Stop (); - + repo.Dispose (); // Remove the process id file File.Delete (SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, "sparkleshare.pid")); diff --git a/SparkleShare/SparkleUI.cs b/SparkleShare/SparkleUI.cs index 1b439188..fb4f2942 100644 --- a/SparkleShare/SparkleUI.cs +++ b/SparkleShare/SparkleUI.cs @@ -445,7 +445,7 @@ namespace SparkleShare { if (repo.Name.Equals (repo_name)) { - repo.Stop (); + repo.Dispose (); Repositories.Remove (repo); repo = null; break;