2010-06-20 21:05:11 +00:00
|
|
|
|
// SparkleShare, an instant update workflow to Git.
|
|
|
|
|
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
|
|
|
//
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2010-11-21 12:33:24 +00:00
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2010-06-20 21:05:11 +00:00
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2010-07-22 21:10:38 +00:00
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2011-02-23 01:13:54 +00:00
|
|
|
|
|
2010-10-10 14:57:12 +00:00
|
|
|
|
using GitSharp;
|
2010-10-10 15:12:01 +00:00
|
|
|
|
using GitSharp.Commands;
|
2010-10-10 19:33:43 +00:00
|
|
|
|
using GitSharp.Core.Transport;
|
2010-09-12 13:00:07 +00:00
|
|
|
|
using Meebey.SmartIrc4net;
|
2010-06-20 21:05:11 +00:00
|
|
|
|
using Mono.Unix;
|
|
|
|
|
using System;
|
2010-09-04 15:23:20 +00:00
|
|
|
|
using System.Collections.Generic;
|
2010-06-20 21:05:11 +00:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using System.Timers;
|
|
|
|
|
|
2010-08-02 15:42:42 +00:00
|
|
|
|
namespace SparkleLib {
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-10-10 14:57:12 +00:00
|
|
|
|
public class SparkleRepo : Repository {
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-08-22 13:28:04 +00:00
|
|
|
|
private Timer RemoteTimer;
|
|
|
|
|
private Timer LocalTimer;
|
2010-06-20 21:05:11 +00:00
|
|
|
|
private FileSystemWatcher Watcher;
|
2010-09-12 13:00:07 +00:00
|
|
|
|
private System.Object ChangeLock;
|
|
|
|
|
private int FetchRequests;
|
2010-09-12 17:46:00 +00:00
|
|
|
|
private SparkleListener Listener;
|
2011-02-26 23:57:48 +00:00
|
|
|
|
private bool HasChanged;
|
|
|
|
|
private List <double> SizeBuffer;
|
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The folder name the repository resides in locally
|
|
|
|
|
/// </summary>
|
|
|
|
|
public readonly string Name;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The folder name the repository resides in remotely
|
|
|
|
|
/// </summary>
|
|
|
|
|
public readonly string RemoteName;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The domain the remote repository is on
|
|
|
|
|
/// </summary>
|
|
|
|
|
public readonly string Domain;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The repository's description
|
|
|
|
|
/// </summary>
|
|
|
|
|
public readonly string Description;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The path where the repository resides locally
|
|
|
|
|
/// </summary>
|
|
|
|
|
public readonly string LocalPath;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The raw url used to sync with.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public readonly string RemoteOriginUrl;
|
|
|
|
|
|
|
|
|
|
private string _CurrentHash;
|
|
|
|
|
private bool _IsSyncing;
|
|
|
|
|
private bool _IsBuffering;
|
|
|
|
|
private bool _IsPolling;
|
|
|
|
|
private bool _IsFetching;
|
|
|
|
|
private bool _IsPushing;
|
|
|
|
|
private bool _HasUnsyncedChanges;
|
2010-10-07 21:31:48 +00:00
|
|
|
|
private bool _ServerOnline;
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The hash of the last commit done in the repository
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string CurrentHash {
|
|
|
|
|
get {
|
|
|
|
|
return _CurrentHash;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The name of the user
|
|
|
|
|
/// </summary>
|
2010-10-10 15:12:01 +00:00
|
|
|
|
public readonly string UserName;
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The name of the user
|
|
|
|
|
/// </summary>
|
2010-10-10 15:12:01 +00:00
|
|
|
|
public readonly string UserEmail;
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Indicates whether the repository is currently waiting for local changes to settle
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsBuffering {
|
|
|
|
|
get {
|
|
|
|
|
return _IsBuffering;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Indicates whether the repository is currently pushing changes
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsPushing {
|
|
|
|
|
get {
|
|
|
|
|
return _IsPushing;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Indicates whether the repository has fallen back to polling the remote repository,
|
|
|
|
|
/// instead of receiving instant notifications
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsPolling {
|
|
|
|
|
get {
|
|
|
|
|
return _IsPolling;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Indicates whether the repository is currently fetching and/or pushing changes
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsSyncing {
|
|
|
|
|
get {
|
|
|
|
|
return _IsSyncing;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Indicates whether the repository is currently fetching remote changes
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsFetching {
|
|
|
|
|
get {
|
|
|
|
|
return _IsFetching;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Indicates whether the repository has local changes that aren't pushed remotely yet
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool HasUnsyncedChanges {
|
|
|
|
|
get {
|
|
|
|
|
return _HasUnsyncedChanges;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-07 21:31:48 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Indicates whether the remote repository is online,
|
|
|
|
|
/// this is based on the result of the Fetch method
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool ServerOnline {
|
|
|
|
|
get {
|
|
|
|
|
return _ServerOnline;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
/// <event cref="Added">
|
|
|
|
|
/// Raised when local files have been added to the repository's staging area
|
|
|
|
|
/// </event>
|
2010-07-20 23:01:09 +00:00
|
|
|
|
public delegate void AddedEventHandler (object o, SparkleEventArgs args);
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
/// <event cref="Commited">
|
|
|
|
|
/// Raised when local files have been added to the repository's index
|
|
|
|
|
/// </event>
|
2010-07-21 23:17:20 +00:00
|
|
|
|
public delegate void CommitedEventHandler (object o, SparkleEventArgs args);
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
/// <event cref="PushingStarted">
|
|
|
|
|
/// Raised when the repository has started pushing changes
|
|
|
|
|
/// </event>
|
2010-07-24 12:32:05 +00:00
|
|
|
|
public delegate void PushingStartedEventHandler (object o, SparkleEventArgs args);
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
/// <event cref="PushingFinished">
|
|
|
|
|
/// Raised when the repository has finished pushing changes
|
|
|
|
|
/// </event>
|
2010-07-24 12:32:05 +00:00
|
|
|
|
public delegate void PushingFinishedEventHandler (object o, SparkleEventArgs args);
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
/// <event cref="PushingFailed">
|
|
|
|
|
/// Raised when pushing changes has failed
|
|
|
|
|
/// </event>
|
2010-08-28 18:07:07 +00:00
|
|
|
|
public delegate void PushingFailedEventHandler (object o, SparkleEventArgs args);
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
/// <event cref="FetchingStarted">
|
|
|
|
|
/// Raised when when the repository has started fetching remote changes
|
|
|
|
|
/// </event>
|
2010-07-22 21:10:38 +00:00
|
|
|
|
public delegate void FetchingStartedEventHandler (object o, SparkleEventArgs args);
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
/// <event cref="FetchingFinished">
|
|
|
|
|
/// Raised when when the repository has finished fetching remote changes
|
|
|
|
|
/// </event>
|
2010-07-22 21:10:38 +00:00
|
|
|
|
public delegate void FetchingFinishedEventHandler (object o, SparkleEventArgs args);
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
2010-10-07 21:43:08 +00:00
|
|
|
|
/// <event cref="FetchingFailed">
|
|
|
|
|
/// Raised when when fetching from the remote repository has failed
|
|
|
|
|
/// </event>
|
|
|
|
|
public delegate void FetchingFailedEventHandler (object o, SparkleEventArgs args);
|
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
/// <event cref="NewCommit">
|
|
|
|
|
/// Raised when the repository has received one or multiple new remote commits
|
|
|
|
|
/// </event>
|
2010-11-02 10:45:10 +00:00
|
|
|
|
public delegate void NewCommitEventHandler (SparkleCommit commit, string repository_path);
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
/// <event cref="ConflictDetected">
|
|
|
|
|
/// Raised when the newly fetched commits are conflicting with local changes
|
|
|
|
|
/// </event>
|
2010-07-24 14:03:58 +00:00
|
|
|
|
public delegate void ConflictDetectedEventHandler (object o, SparkleEventArgs args);
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
/// <event cref="ChangesDetected">
|
|
|
|
|
/// Raised when local files have changed in the repository's folder
|
|
|
|
|
/// </event>
|
2010-08-28 18:07:07 +00:00
|
|
|
|
public delegate void ChangesDetectedEventHandler (object o, SparkleEventArgs args);
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
|
|
|
|
/// <event cref="CommitEndedUpEmpty">
|
|
|
|
|
/// 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.
|
|
|
|
|
/// </event>
|
2010-08-28 18:56:19 +00:00
|
|
|
|
public delegate void CommitEndedUpEmptyEventHandler (object o, SparkleEventArgs args);
|
2010-07-21 23:17:20 +00:00
|
|
|
|
|
2010-07-24 14:03:58 +00:00
|
|
|
|
public event AddedEventHandler Added;
|
|
|
|
|
public event CommitedEventHandler Commited;
|
|
|
|
|
public event PushingStartedEventHandler PushingStarted;
|
|
|
|
|
public event PushingFinishedEventHandler PushingFinished;
|
2010-08-28 18:07:07 +00:00
|
|
|
|
public event PushingFailedEventHandler PushingFailed;
|
2010-07-24 14:03:58 +00:00
|
|
|
|
public event FetchingStartedEventHandler FetchingStarted;
|
|
|
|
|
public event FetchingFinishedEventHandler FetchingFinished;
|
2010-10-07 21:43:08 +00:00
|
|
|
|
public event FetchingFailedEventHandler FetchingFailed;
|
2010-07-24 14:03:58 +00:00
|
|
|
|
public event NewCommitEventHandler NewCommit;
|
|
|
|
|
public event ConflictDetectedEventHandler ConflictDetected;
|
2010-08-28 18:07:07 +00:00
|
|
|
|
public event ChangesDetectedEventHandler ChangesDetected;
|
2010-08-28 18:56:19 +00:00
|
|
|
|
public event CommitEndedUpEmptyEventHandler CommitEndedUpEmpty;
|
2010-07-20 23:01:09 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-10-10 14:57:12 +00:00
|
|
|
|
public SparkleRepo (string path) : base (path)
|
2010-06-20 21:05:11 +00:00
|
|
|
|
{
|
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
LocalPath = path;
|
|
|
|
|
Name = Path.GetFileName (LocalPath);
|
2010-09-20 18:53:49 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
RemoteName = Path.GetFileNameWithoutExtension (RemoteOriginUrl);
|
|
|
|
|
RemoteOriginUrl = Config ["remote.origin.url"];
|
|
|
|
|
Domain = GetDomain (RemoteOriginUrl);
|
|
|
|
|
Description = GetDescription ();
|
|
|
|
|
UserName = Config ["user.name"];
|
|
|
|
|
UserEmail = Config ["user.email"];
|
2011-02-01 09:20:30 +00:00
|
|
|
|
|
2011-02-01 09:38:56 +00:00
|
|
|
|
if (Head.CurrentCommit == null)
|
2011-02-26 14:20:32 +00:00
|
|
|
|
_CurrentHash = null;
|
2011-02-01 09:38:56 +00:00
|
|
|
|
else
|
2011-02-26 14:20:32 +00:00
|
|
|
|
_CurrentHash = Head.CurrentCommit.Hash;
|
2011-02-01 09:20:30 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
_IsSyncing = false;
|
|
|
|
|
_IsBuffering = false;
|
|
|
|
|
_IsPolling = true;
|
|
|
|
|
_IsFetching = false;
|
|
|
|
|
_IsPushing = false;
|
|
|
|
|
_ServerOnline = true;
|
|
|
|
|
|
|
|
|
|
HasChanged = false;
|
|
|
|
|
ChangeLock = new Object ();
|
|
|
|
|
FetchRequests = 0;
|
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
|
2010-10-06 23:54:42 +00:00
|
|
|
|
string unsynced_file_path = SparkleHelpers.CombineMore (LocalPath ,
|
|
|
|
|
".git", "has_unsynced_changes");
|
|
|
|
|
|
|
|
|
|
if (File.Exists (unsynced_file_path))
|
|
|
|
|
_HasUnsyncedChanges = true;
|
|
|
|
|
else
|
|
|
|
|
_HasUnsyncedChanges = false;
|
|
|
|
|
|
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
if (_CurrentHash == null)
|
2010-08-08 19:16:48 +00:00
|
|
|
|
CreateInitialCommit ();
|
2010-07-21 23:17:20 +00:00
|
|
|
|
|
2010-07-30 09:57:33 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
// Watch the repository's folder
|
2010-07-20 21:21:37 +00:00
|
|
|
|
Watcher = new FileSystemWatcher (LocalPath) {
|
|
|
|
|
IncludeSubdirectories = true,
|
|
|
|
|
EnableRaisingEvents = true,
|
|
|
|
|
Filter = "*"
|
|
|
|
|
};
|
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
Watcher.Changed += new FileSystemEventHandler (OnFileActivity);
|
|
|
|
|
Watcher.Created += new FileSystemEventHandler (OnFileActivity);
|
|
|
|
|
Watcher.Deleted += new FileSystemEventHandler (OnFileActivity);
|
2010-08-29 10:38:34 +00:00
|
|
|
|
Watcher.Renamed += new RenamedEventHandler (OnFileActivity);
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
// Listen to the irc channel on the server...
|
2010-10-10 15:12:01 +00:00
|
|
|
|
Listener = new SparkleListener (Domain, "#" + RemoteName, UserEmail);
|
2010-10-03 10:43:28 +00:00
|
|
|
|
|
2011-03-01 23:13:43 +00:00
|
|
|
|
// ...fetch remote changes every 60 seconds if that fails
|
2011-02-26 14:20:32 +00:00
|
|
|
|
RemoteTimer = new Timer () {
|
2011-03-01 23:13:43 +00:00
|
|
|
|
Interval = 60000
|
2011-02-26 14:20:32 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2010-08-22 13:28:04 +00:00
|
|
|
|
RemoteTimer.Elapsed += delegate {
|
2011-03-01 23:13:43 +00:00
|
|
|
|
|
|
|
|
|
if (_IsPolling) {
|
|
|
|
|
|
2010-10-09 16:36:51 +00:00
|
|
|
|
CheckForRemoteChanges ();
|
2011-03-01 23:13:43 +00:00
|
|
|
|
|
|
|
|
|
if (!Listener.Client.IsConnected) {
|
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Trying to reconnect...");
|
|
|
|
|
Listener.Listen ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
2010-10-09 16:36:51 +00:00
|
|
|
|
if (_HasUnsyncedChanges)
|
2010-08-28 18:07:07 +00:00
|
|
|
|
Push ();
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
2010-10-03 10:43:28 +00:00
|
|
|
|
};
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
|
|
|
|
// Stop polling when the connection to the irc channel is succesful
|
2010-09-12 17:46:00 +00:00
|
|
|
|
Listener.Client.OnConnected += delegate {
|
2011-03-01 23:13:43 +00:00
|
|
|
|
|
|
|
|
|
_IsPolling = false;
|
|
|
|
|
|
2010-10-07 19:40:23 +00:00
|
|
|
|
// Check for changes manually one more time
|
|
|
|
|
CheckForRemoteChanges ();
|
|
|
|
|
|
|
|
|
|
// Push changes that were made since the last disconnect
|
|
|
|
|
if (_HasUnsyncedChanges)
|
|
|
|
|
Push ();
|
|
|
|
|
|
2011-03-01 23:13:43 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Connected. Now listening... (" + Listener.Server + ")");
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
2011-03-01 23:13:43 +00:00
|
|
|
|
// Start polling when the connection to the irc channel is lost
|
|
|
|
|
Listener.Client.OnConnectionError += delegate {
|
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Lost connection. Falling back to polling...");
|
|
|
|
|
_IsPolling = true;
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
2010-09-12 13:00:07 +00:00
|
|
|
|
// Start polling when the connection to the irc channel is lost
|
2010-09-12 17:46:00 +00:00
|
|
|
|
Listener.Client.OnDisconnected += delegate {
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Lost connection. Falling back to polling...");
|
2010-09-14 19:11:55 +00:00
|
|
|
|
_IsPolling = true;
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Fetch changes when there is a message in the irc channel
|
2010-09-20 18:53:49 +00:00
|
|
|
|
Listener.Client.OnChannelMessage += delegate (object o, IrcEventArgs args) {
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Irc", "[" + Name + "] Was notified of a remote change.");
|
2011-03-01 23:13:43 +00:00
|
|
|
|
string message = args.Data.Message.Trim ();
|
|
|
|
|
|
|
|
|
|
if (!message.Equals (_CurrentHash) && message.Length == 40) {
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
|
|
|
|
FetchRequests++;
|
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
if (!_IsFetching) {
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
|
|
|
|
while (FetchRequests > 0) {
|
2010-07-21 23:17:20 +00:00
|
|
|
|
|
2010-09-12 13:00:07 +00:00
|
|
|
|
Fetch ();
|
|
|
|
|
FetchRequests--;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Rebase ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
2011-02-27 00:53:14 +00:00
|
|
|
|
|
|
|
|
|
// Not really needed as we won't be notified about our own messages
|
2010-09-12 13:00:07 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Irc",
|
2010-09-14 19:11:55 +00:00
|
|
|
|
"[" + Name + "] False alarm, already up to date. (" + _CurrentHash + ")");
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Start listening
|
2011-02-27 01:01:13 +00:00
|
|
|
|
Listener.Listen ();
|
2011-02-26 23:57:48 +00:00
|
|
|
|
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
2011-02-26 23:57:48 +00:00
|
|
|
|
SizeBuffer = new List <double> ();
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
|
|
|
|
// Keep a timer that checks if there are changes and
|
2010-07-20 21:21:37 +00:00
|
|
|
|
// whether they have settled
|
2010-08-22 13:28:04 +00:00
|
|
|
|
LocalTimer = new Timer () {
|
2011-02-26 23:57:48 +00:00
|
|
|
|
Interval = 250
|
2010-07-20 21:21:37 +00:00
|
|
|
|
};
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-08-22 13:28:04 +00:00
|
|
|
|
LocalTimer.Elapsed += delegate (object o, ElapsedEventArgs args) {
|
2010-07-20 21:21:37 +00:00
|
|
|
|
CheckForChanges ();
|
2010-06-20 21:05:11 +00:00
|
|
|
|
};
|
|
|
|
|
|
2010-09-12 13:00:07 +00:00
|
|
|
|
|
2011-03-01 23:13:43 +00:00
|
|
|
|
RemoteTimer.Start ();
|
2010-08-22 13:28:04 +00:00
|
|
|
|
LocalTimer.Start ();
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
|
|
|
|
// Add everything that changed
|
2010-08-08 14:45:28 +00:00
|
|
|
|
// since SparkleShare was stopped
|
2010-06-20 21:05:11 +00:00
|
|
|
|
AddCommitAndPush ();
|
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
if (_CurrentHash == null)
|
2010-10-10 16:19:23 +00:00
|
|
|
|
_CurrentHash = Head.CurrentCommit.Hash;
|
2010-08-08 19:16:48 +00:00
|
|
|
|
|
2010-07-20 21:21:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-08-22 13:28:04 +00:00
|
|
|
|
private void CheckForRemoteChanges ()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Checking for remote changes...");
|
2011-02-26 14:20:32 +00:00
|
|
|
|
SparkleGit git = new SparkleGit (LocalPath, "ls-remote origin master");
|
|
|
|
|
|
|
|
|
|
git.Exited += delegate {
|
2010-08-23 08:42:34 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
if (git.ExitCode != 0)
|
2010-08-23 08:42:34 +00:00
|
|
|
|
return;
|
2010-08-22 13:28:04 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
string remote_hash = git.StandardOutput.ReadToEnd ();
|
2010-08-22 13:28:04 +00:00
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
if (!remote_hash.StartsWith (_CurrentHash)) {
|
2010-08-22 13:28:04 +00:00
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Remote changes found.");
|
|
|
|
|
Fetch ();
|
2010-09-12 13:00:07 +00:00
|
|
|
|
Rebase ();
|
2010-08-22 13:28:04 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
2010-08-22 13:28:04 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
git.Start ();
|
2011-02-26 23:57:48 +00:00
|
|
|
|
git.WaitForExit ();
|
2010-10-10 15:43:54 +00:00
|
|
|
|
|
2010-08-22 13:28:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-07-20 21:21:37 +00:00
|
|
|
|
private void CheckForChanges ()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
lock (ChangeLock) {
|
|
|
|
|
|
|
|
|
|
if (HasChanged) {
|
2011-02-26 23:57:48 +00:00
|
|
|
|
|
|
|
|
|
if (SizeBuffer.Count >= 4)
|
|
|
|
|
SizeBuffer.RemoveAt (0);
|
|
|
|
|
|
|
|
|
|
DirectoryInfo dir_info = new DirectoryInfo (LocalPath);
|
|
|
|
|
SizeBuffer.Add (CalculateFolderSize (dir_info));
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2011-02-26 23:57:48 +00:00
|
|
|
|
if (SizeBuffer [0].Equals (SizeBuffer [1]) &&
|
|
|
|
|
SizeBuffer [1].Equals (SizeBuffer [2]) &&
|
|
|
|
|
SizeBuffer [2].Equals (SizeBuffer [3])) {
|
2010-08-28 18:56:19 +00:00
|
|
|
|
|
2011-02-26 23:57:48 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Local", "[" + Name + "] Changes have settled.");
|
2010-08-28 18:56:19 +00:00
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
_IsBuffering = false;
|
2010-09-08 22:30:24 +00:00
|
|
|
|
|
2010-08-28 18:56:19 +00:00
|
|
|
|
HasChanged = false;
|
2010-07-20 21:21:37 +00:00
|
|
|
|
AddCommitAndPush ();
|
2010-08-28 18:56:19 +00:00
|
|
|
|
|
2010-07-20 21:21:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-09-12 13:00:07 +00:00
|
|
|
|
// Starts a timer when something changes
|
2010-08-28 18:07:07 +00:00
|
|
|
|
private void OnFileActivity (object o, FileSystemEventArgs fse_args)
|
2010-06-20 21:05:11 +00:00
|
|
|
|
{
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-08-28 18:07:07 +00:00
|
|
|
|
WatcherChangeTypes wct = fse_args.ChangeType;
|
2011-02-26 18:46:08 +00:00
|
|
|
|
|
|
|
|
|
int number_of_changes = Status.Untracked.Count +
|
|
|
|
|
Status.Missing.Count +
|
|
|
|
|
Status.Modified.Count;
|
|
|
|
|
|
|
|
|
|
if (number_of_changes > 0) {
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
_IsBuffering = true;
|
2010-09-08 22:30:24 +00:00
|
|
|
|
|
2010-08-28 18:07:07 +00:00
|
|
|
|
// Only fire the event if the timer has been stopped.
|
|
|
|
|
// This prevents multiple events from being raised whilst "buffering".
|
|
|
|
|
if (!HasChanged) {
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-08-28 18:07:07 +00:00
|
|
|
|
SparkleEventArgs args = new SparkleEventArgs ("ChangesDetected");
|
2010-08-28 18:56:19 +00:00
|
|
|
|
|
2010-08-28 18:07:07 +00:00
|
|
|
|
if (ChangesDetected != null)
|
|
|
|
|
ChangesDetected (this, args);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Event", "[" + Name + "] " + wct.ToString () + " '" + fse_args.Name + "'");
|
2011-02-26 23:57:48 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Local", "[" + Name + "] Changes found, checking if settled.");
|
|
|
|
|
|
2010-08-22 13:28:04 +00:00
|
|
|
|
RemoteTimer.Stop ();
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
|
|
|
|
lock (ChangeLock) {
|
2010-07-24 14:03:58 +00:00
|
|
|
|
|
2010-07-03 19:37:43 +00:00
|
|
|
|
HasChanged = true;
|
2010-07-24 14:03:58 +00:00
|
|
|
|
|
2010-07-03 19:37:43 +00:00
|
|
|
|
}
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-08-28 18:56:19 +00:00
|
|
|
|
// When there are changes we generally want to Add, Commit and Push,
|
2010-07-20 21:21:37 +00:00
|
|
|
|
// so this method does them all with appropriate timers, etc. switched off
|
2010-06-20 21:05:11 +00:00
|
|
|
|
public void AddCommitAndPush ()
|
|
|
|
|
{
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-07-03 19:37:43 +00:00
|
|
|
|
try {
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-08-22 13:28:04 +00:00
|
|
|
|
LocalTimer.Stop ();
|
|
|
|
|
RemoteTimer.Stop ();
|
2010-07-03 19:37:43 +00:00
|
|
|
|
|
2011-02-23 01:13:54 +00:00
|
|
|
|
if (Status.AnyDifferences) {
|
2011-02-23 00:09:44 +00:00
|
|
|
|
|
|
|
|
|
Add ();
|
|
|
|
|
|
|
|
|
|
string message = FormatCommitMessage ();
|
2010-07-20 21:21:37 +00:00
|
|
|
|
Commit (message);
|
2011-02-23 00:09:44 +00:00
|
|
|
|
|
2010-07-03 19:37:43 +00:00
|
|
|
|
Push ();
|
2010-07-24 14:03:58 +00:00
|
|
|
|
|
2010-08-28 18:56:19 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
SparkleEventArgs args = new SparkleEventArgs ("CommitEndedUpEmpty");
|
|
|
|
|
|
|
|
|
|
if (CommitEndedUpEmpty != null)
|
|
|
|
|
CommitEndedUpEmpty (this, args);
|
|
|
|
|
|
2010-07-03 19:37:43 +00:00
|
|
|
|
}
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
2011-03-01 23:13:43 +00:00
|
|
|
|
RemoteTimer.Start ();
|
2010-08-22 13:28:04 +00:00
|
|
|
|
LocalTimer.Start ();
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
// Stages the made changes
|
|
|
|
|
private void Add ()
|
|
|
|
|
{
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Staging changes...");
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-10-10 15:43:54 +00:00
|
|
|
|
// FIXME: this GitSharp method seems to block...
|
|
|
|
|
// Index.AddAll ();
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
|
|
|
|
SparkleGit git = new SparkleGit (LocalPath, "add --all");
|
|
|
|
|
git.Start ();
|
|
|
|
|
git.WaitForExit ();
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes staged.");
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-07-21 23:17:20 +00:00
|
|
|
|
SparkleEventArgs args = new SparkleEventArgs ("Added");
|
|
|
|
|
|
2010-07-20 23:01:09 +00:00
|
|
|
|
if (Added != null)
|
|
|
|
|
Added (this, args);
|
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2011-02-10 02:29:07 +00:00
|
|
|
|
// Removes unneeded objects
|
|
|
|
|
private void CollectGarbage ()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Collecting garbage...");
|
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
SparkleGit git = new SparkleGit (LocalPath, "gc");
|
|
|
|
|
git.Start ();
|
|
|
|
|
git.WaitForExit ();
|
2011-02-10 02:29:07 +00:00
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Garbage collected..");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
// Commits the made changes
|
2010-10-10 14:57:12 +00:00
|
|
|
|
new public void Commit (string message)
|
2010-06-20 21:05:11 +00:00
|
|
|
|
{
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-10-10 14:57:12 +00:00
|
|
|
|
if (!Status.AnyDifferences)
|
2010-08-29 10:38:34 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2010-10-10 14:57:12 +00:00
|
|
|
|
base.Commit (message);
|
2011-02-27 00:53:14 +00:00
|
|
|
|
_CurrentHash = Head.CurrentCommit.Hash;
|
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Commit", "[" + Name + "] " + message + " (" + _CurrentHash);
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2011-02-10 02:29:07 +00:00
|
|
|
|
SparkleEventArgs args = new SparkleEventArgs ("Commited") {
|
|
|
|
|
Message = message
|
|
|
|
|
};
|
2010-07-21 23:17:20 +00:00
|
|
|
|
|
|
|
|
|
if (Commited != null)
|
2010-07-24 14:03:58 +00:00
|
|
|
|
Commited (this, args);
|
2011-02-10 02:29:07 +00:00
|
|
|
|
|
|
|
|
|
// Collect garbage pseudo-randomly
|
2011-02-11 01:31:10 +00:00
|
|
|
|
if (DateTime.Now.Second % 10 == 0)
|
2011-02-10 02:29:07 +00:00
|
|
|
|
CollectGarbage ();
|
2010-07-21 23:17:20 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-07-24 21:31:24 +00:00
|
|
|
|
// Fetches changes from the remote repository
|
2010-06-20 21:05:11 +00:00
|
|
|
|
public void Fetch ()
|
|
|
|
|
{
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
_IsSyncing = true;
|
|
|
|
|
_IsFetching = true;
|
2010-09-08 22:30:24 +00:00
|
|
|
|
|
2010-08-22 13:28:04 +00:00
|
|
|
|
RemoteTimer.Stop ();
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Fetching changes...");
|
2010-10-10 19:33:43 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
SparkleGit git = new SparkleGit (LocalPath, "fetch -v origin master");
|
2010-07-22 21:10:38 +00:00
|
|
|
|
|
2010-08-05 21:46:48 +00:00
|
|
|
|
SparkleEventArgs args;
|
|
|
|
|
args = new SparkleEventArgs ("FetchingStarted");
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-08-05 21:46:48 +00:00
|
|
|
|
if (FetchingStarted != null)
|
|
|
|
|
FetchingStarted (this, args);
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
git.Exited += delegate {
|
2010-08-05 10:40:12 +00:00
|
|
|
|
|
2010-08-05 21:46:48 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes fetched.");
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
_IsSyncing = false;
|
|
|
|
|
_IsFetching = false;
|
2010-09-11 09:52:10 +00:00
|
|
|
|
|
2010-10-10 16:19:23 +00:00
|
|
|
|
_CurrentHash = Head.CurrentCommit.Hash;
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
if (git.ExitCode != 0) {
|
2010-10-07 21:43:08 +00:00
|
|
|
|
|
2010-10-07 21:31:48 +00:00
|
|
|
|
_ServerOnline = false;
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
|
|
|
|
args = new SparkleEventArgs ("FetchingFailed");
|
|
|
|
|
|
2010-10-07 21:43:08 +00:00
|
|
|
|
if (FetchingFailed != null)
|
|
|
|
|
FetchingFailed (this, args);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
2010-10-07 21:31:48 +00:00
|
|
|
|
_ServerOnline = true;
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
|
|
|
|
args = new SparkleEventArgs ("FetchingFinished");
|
2010-10-07 21:31:48 +00:00
|
|
|
|
|
2010-10-07 21:43:08 +00:00
|
|
|
|
if (FetchingFinished != null)
|
|
|
|
|
FetchingFinished (this, args);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-01 23:13:43 +00:00
|
|
|
|
RemoteTimer.Start ();
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
2010-08-05 21:46:48 +00:00
|
|
|
|
};
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
|
|
|
|
git.Start ();
|
|
|
|
|
git.WaitForExit ();
|
2011-02-02 07:39:50 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-07-21 23:17:20 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
// Merges the fetched changes
|
|
|
|
|
public void Rebase ()
|
|
|
|
|
{
|
2011-03-02 00:24:18 +00:00
|
|
|
|
|
|
|
|
|
Watcher.EnableRaisingEvents = false;
|
2011-02-23 00:09:44 +00:00
|
|
|
|
|
2011-02-23 01:13:54 +00:00
|
|
|
|
if (Status.AnyDifferences) {
|
2011-02-23 00:09:44 +00:00
|
|
|
|
|
|
|
|
|
Add ();
|
2011-02-23 00:21:30 +00:00
|
|
|
|
|
|
|
|
|
string commit_message = FormatCommitMessage ();
|
|
|
|
|
Commit (commit_message);
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2011-02-23 00:09:44 +00:00
|
|
|
|
}
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Rebasing changes...");
|
2011-02-26 14:20:32 +00:00
|
|
|
|
SparkleGit git = new SparkleGit (LocalPath, "rebase -v FETCH_HEAD");
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
git.Exited += delegate {
|
2011-03-01 23:42:00 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
if (Status.MergeConflict.Count > 0) {
|
2011-02-26 23:57:48 +00:00
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict detected...");
|
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
foreach (string problem_file_name in Status.MergeConflict) {
|
|
|
|
|
|
|
|
|
|
SparkleGit git_ours = new SparkleGit (LocalPath,
|
|
|
|
|
"checkout --ours " + problem_file_name);
|
|
|
|
|
git_ours.Start ();
|
|
|
|
|
git_ours.WaitForExit ();
|
|
|
|
|
|
|
|
|
|
string timestamp = DateTime.Now.ToString ("H:mm d MMM");
|
|
|
|
|
|
|
|
|
|
string new_file_name = problem_file_name + " (" + UserName + ", " + timestamp + ")";
|
|
|
|
|
File.Move (problem_file_name, new_file_name);
|
|
|
|
|
|
|
|
|
|
SparkleGit git_theirs = new SparkleGit (LocalPath,
|
|
|
|
|
"checkout --theirs " + problem_file_name);
|
|
|
|
|
git_theirs.Start ();
|
|
|
|
|
git_theirs.WaitForExit ();
|
|
|
|
|
|
|
|
|
|
SparkleEventArgs args = new SparkleEventArgs ("ConflictDetected");
|
|
|
|
|
|
|
|
|
|
if (ConflictDetected != null)
|
|
|
|
|
ConflictDetected (this, args);
|
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
Add ();
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
|
|
|
|
SparkleGit git_continue = new SparkleGit (LocalPath, "rebase --continue");
|
|
|
|
|
git_continue.Start ();
|
|
|
|
|
git_continue.WaitForExit ();
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict resolved.");
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
Push ();
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
git.Start ();
|
|
|
|
|
git.WaitForExit ();
|
2011-03-01 23:42:00 +00:00
|
|
|
|
|
|
|
|
|
_CurrentHash = Head.CurrentCommit.Hash;
|
|
|
|
|
|
|
|
|
|
if (NewCommit != null)
|
|
|
|
|
NewCommit (GetCommits (2) [0], LocalPath); // FIXME: GetCommits doesn't like 1
|
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes rebased.");
|
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
Watcher.EnableRaisingEvents = true;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-21 23:17:20 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
// Pushes the changes to the remote repo
|
|
|
|
|
public void Push ()
|
|
|
|
|
{
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
_IsSyncing = true;
|
|
|
|
|
_IsPushing = true;
|
2011-02-12 23:40:38 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
SparkleGit git = new SparkleGit (LocalPath, "push origin master");
|
2010-07-24 12:32:05 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Pushing changes...");
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
SparkleEventArgs args = new SparkleEventArgs ("PushingStarted");
|
2010-10-10 22:04:08 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
if (PushingStarted != null)
|
|
|
|
|
PushingStarted (this, args);
|
2010-09-08 22:30:24 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
|
|
|
|
git.Exited += delegate {
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
_IsSyncing = false;
|
|
|
|
|
_IsPushing = false;
|
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
if (git.ExitCode != 0) {
|
2010-08-28 18:07:07 +00:00
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Pushing failed.");
|
|
|
|
|
|
2010-10-06 23:54:42 +00:00
|
|
|
|
string unsynced_file_path = SparkleHelpers.CombineMore (LocalPath ,
|
|
|
|
|
".git", "has_unsynced_changes");
|
|
|
|
|
|
|
|
|
|
if (!File.Exists (unsynced_file_path))
|
|
|
|
|
File.Create (unsynced_file_path);
|
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
_HasUnsyncedChanges = true;
|
2010-07-21 23:17:20 +00:00
|
|
|
|
|
2010-08-28 18:07:07 +00:00
|
|
|
|
args = new SparkleEventArgs ("PushingFailed");
|
|
|
|
|
|
|
|
|
|
if (PushingFailed != null)
|
2011-02-27 00:53:14 +00:00
|
|
|
|
PushingFailed (this, args);
|
|
|
|
|
|
|
|
|
|
CheckForChanges ();
|
2010-08-28 18:07:07 +00:00
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes pushed.");
|
|
|
|
|
|
|
|
|
|
args = new SparkleEventArgs ("PushingFinished");
|
|
|
|
|
|
2010-10-06 23:54:42 +00:00
|
|
|
|
string unsynced_file_path = SparkleHelpers.CombineMore (LocalPath ,
|
|
|
|
|
".git", "has_unsynced_changes");
|
|
|
|
|
|
2010-10-07 21:31:48 +00:00
|
|
|
|
if (File.Exists (unsynced_file_path))
|
|
|
|
|
File.Delete (unsynced_file_path);
|
2010-10-06 23:54:42 +00:00
|
|
|
|
|
2010-10-07 21:31:48 +00:00
|
|
|
|
_HasUnsyncedChanges = false;
|
2010-08-28 18:07:07 +00:00
|
|
|
|
|
|
|
|
|
if (PushingFinished != null)
|
|
|
|
|
PushingFinished (this, args);
|
2011-02-27 00:53:14 +00:00
|
|
|
|
|
|
|
|
|
if (!_IsPolling)
|
2011-02-27 01:01:13 +00:00
|
|
|
|
Listener.Announce (_CurrentHash);
|
2010-08-28 18:07:07 +00:00
|
|
|
|
|
|
|
|
|
}
|
2010-07-21 23:17:20 +00:00
|
|
|
|
|
2010-07-24 12:32:05 +00:00
|
|
|
|
};
|
2011-02-26 14:20:32 +00:00
|
|
|
|
|
2011-02-12 23:40:38 +00:00
|
|
|
|
|
2011-02-26 14:20:32 +00:00
|
|
|
|
git.Start ();
|
|
|
|
|
git.WaitForExit ();
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-07-20 21:21:37 +00:00
|
|
|
|
|
2010-07-24 21:31:24 +00:00
|
|
|
|
// Gets the domain name of a given URL
|
2010-10-10 19:33:43 +00:00
|
|
|
|
private string GetDomain (string url)
|
2010-07-21 23:17:20 +00:00
|
|
|
|
{
|
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
if (url.Equals (""))
|
2010-10-10 22:04:08 +00:00
|
|
|
|
return null;
|
2010-08-08 19:16:48 +00:00
|
|
|
|
|
2010-09-14 19:11:55 +00:00
|
|
|
|
string domain = url.Substring (url.IndexOf ("@") + 1);
|
2010-07-21 23:17:20 +00:00
|
|
|
|
|
2011-02-06 01:10:15 +00:00
|
|
|
|
if (domain.Contains (":"))
|
2010-07-21 23:17:20 +00:00
|
|
|
|
domain = domain.Substring (0, domain.IndexOf (":"));
|
|
|
|
|
else
|
|
|
|
|
domain = domain.Substring (0, domain.IndexOf ("/"));
|
|
|
|
|
|
|
|
|
|
return domain;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-08-14 20:02:00 +00:00
|
|
|
|
// Gets the repository's description
|
2010-10-10 19:33:43 +00:00
|
|
|
|
private string GetDescription ()
|
2010-08-14 20:02:00 +00:00
|
|
|
|
{
|
|
|
|
|
|
2010-10-10 19:33:43 +00:00
|
|
|
|
string description_file_path = SparkleHelpers.CombineMore (Directory, "description");
|
2010-08-14 20:02:00 +00:00
|
|
|
|
|
|
|
|
|
if (!File.Exists (description_file_path))
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
StreamReader reader = new StreamReader (description_file_path);
|
|
|
|
|
string description = reader.ReadToEnd ();
|
|
|
|
|
reader.Close ();
|
|
|
|
|
|
|
|
|
|
if (description.StartsWith ("Unnamed"))
|
|
|
|
|
description = null;
|
|
|
|
|
|
|
|
|
|
return description;
|
|
|
|
|
|
|
|
|
|
}
|
2011-02-26 23:57:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Recursively gets a folder's size in bytes
|
|
|
|
|
private double CalculateFolderSize (DirectoryInfo parent)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (!System.IO.Directory.Exists (parent.ToString ()))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
double size = 0;
|
|
|
|
|
|
|
|
|
|
// Ignore the temporary 'rebase-apply' directory. This prevents potential
|
|
|
|
|
// crashes when files are being queried whilst the files have already been deleted.
|
|
|
|
|
if (parent.Name.Equals ("rebase-apply"))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
foreach (FileInfo file in parent.GetFiles()) {
|
|
|
|
|
|
|
|
|
|
if (!file.Exists)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
size += file.Length;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (DirectoryInfo directory in parent.GetDirectories())
|
|
|
|
|
size += CalculateFolderSize (directory);
|
|
|
|
|
|
|
|
|
|
return size;
|
|
|
|
|
|
|
|
|
|
}
|
2010-08-14 20:02:00 +00:00
|
|
|
|
|
|
|
|
|
|
2010-08-08 19:16:48 +00:00
|
|
|
|
// Create a first commit in case the user has cloned
|
|
|
|
|
// an empty repository
|
|
|
|
|
private void CreateInitialCommit ()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
TextWriter writer = new StreamWriter (Path.Combine (LocalPath, "SparkleShare.txt"));
|
|
|
|
|
writer.WriteLine (":)");
|
|
|
|
|
writer.Close ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-09-04 15:23:20 +00:00
|
|
|
|
// Returns a list of latest commits
|
2010-10-10 19:33:43 +00:00
|
|
|
|
public List <SparkleCommit> GetCommits (int count)
|
2010-09-04 15:23:20 +00:00
|
|
|
|
{
|
|
|
|
|
|
2011-02-27 18:50:42 +00:00
|
|
|
|
if (count < 1)
|
|
|
|
|
count = 30;
|
|
|
|
|
|
2010-09-04 15:23:20 +00:00
|
|
|
|
List <SparkleCommit> commits = new List <SparkleCommit> ();
|
|
|
|
|
|
2011-02-27 18:50:42 +00:00
|
|
|
|
SparkleGit git_log = new SparkleGit (LocalPath, "log -" + count + " --raw --date=iso");
|
|
|
|
|
git_log.Start ();
|
|
|
|
|
git_log.WaitForExit ();
|
|
|
|
|
|
|
|
|
|
string output = git_log.StandardOutput.ReadToEnd ();
|
|
|
|
|
string [] lines = output.Split ("\n".ToCharArray ());
|
|
|
|
|
|
|
|
|
|
List <string> entries = new List <string> ();
|
2010-09-04 15:23:20 +00:00
|
|
|
|
|
2011-02-27 18:50:42 +00:00
|
|
|
|
int j = 0;
|
|
|
|
|
string entry = "";
|
|
|
|
|
foreach (string line in lines) {
|
|
|
|
|
|
|
|
|
|
if (line.StartsWith ("commit") && j > 0) {
|
2010-11-27 17:44:13 +00:00
|
|
|
|
|
2011-02-27 18:50:42 +00:00
|
|
|
|
entries.Add (entry);
|
|
|
|
|
entry = "";
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entry += line + "\n";
|
|
|
|
|
j++;
|
2010-09-04 15:23:20 +00:00
|
|
|
|
|
2011-02-27 18:50:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-10-10 21:39:00 +00:00
|
|
|
|
|
2011-02-27 18:50:42 +00:00
|
|
|
|
foreach (string log_entry in entries) {
|
2010-09-04 15:23:20 +00:00
|
|
|
|
|
2011-03-02 00:24:18 +00:00
|
|
|
|
Regex regex = new Regex (@"commit ([a-z0-9]{40})\n" +
|
2011-02-27 18:50:42 +00:00
|
|
|
|
"Author: (.+) <(.+)>\n" +
|
|
|
|
|
"Date: ([0-9]{4})-([0-9]{2})-([0-9]{2}) " +
|
|
|
|
|
"([0-9]{2}):([0-9]{2}):([0-9]{2}) \\+([0-9]{4})\n" +
|
|
|
|
|
"*");
|
|
|
|
|
|
|
|
|
|
Match match = regex.Match (log_entry);
|
2010-10-10 21:39:00 +00:00
|
|
|
|
|
2011-02-27 18:50:42 +00:00
|
|
|
|
if (match.Success) {
|
2010-09-04 15:23:20 +00:00
|
|
|
|
|
2011-02-27 18:50:42 +00:00
|
|
|
|
SparkleCommit commit = new SparkleCommit ();
|
|
|
|
|
|
|
|
|
|
commit.Hash = match.Groups [1].Value;
|
|
|
|
|
commit.UserName = match.Groups [2].Value;
|
|
|
|
|
commit.UserEmail = match.Groups [3].Value;
|
|
|
|
|
|
|
|
|
|
commit.DateTime = new DateTime (int.Parse (match.Groups [4].Value),
|
|
|
|
|
int.Parse (match.Groups [5].Value), int.Parse (match.Groups [6].Value),
|
|
|
|
|
int.Parse (match.Groups [7].Value), int.Parse (match.Groups [8].Value),
|
|
|
|
|
int.Parse (match.Groups [9].Value));
|
|
|
|
|
|
|
|
|
|
string [] entry_lines = log_entry.Split ("\n".ToCharArray ());
|
|
|
|
|
foreach (string entry_line in entry_lines) {
|
|
|
|
|
|
|
|
|
|
if (entry_line.StartsWith (":")) {
|
|
|
|
|
|
2011-03-01 23:13:43 +00:00
|
|
|
|
string change_type = entry_line [37].ToString ();
|
|
|
|
|
string file_path = entry_line.Substring (39);
|
2011-02-27 18:50:42 +00:00
|
|
|
|
|
|
|
|
|
if (change_type.Equals ("A")) {
|
|
|
|
|
|
|
|
|
|
commit.Added.Add (file_path);
|
|
|
|
|
|
|
|
|
|
} else if (change_type.Equals ("M")) {
|
|
|
|
|
|
|
|
|
|
commit.Edited.Add (file_path);
|
|
|
|
|
|
|
|
|
|
} else if (change_type.Equals ("D")) {
|
|
|
|
|
|
|
|
|
|
commit.Deleted.Add (file_path);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
commits.Add (commit);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-04 15:23:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return commits;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
// Creates a pretty commit message based on what has changed
|
|
|
|
|
private string FormatCommitMessage ()
|
|
|
|
|
{
|
|
|
|
|
|
2010-11-27 20:24:57 +00:00
|
|
|
|
// RepositoryStatus contains the following properties (all HashSet <string>)
|
|
|
|
|
//
|
|
|
|
|
// * Added ---> added and staged
|
|
|
|
|
// * MergeConflict --->
|
|
|
|
|
// * Missing ---> removed but not staged
|
|
|
|
|
// * Modified ---> modified but not staged
|
|
|
|
|
// * Removed ---> removed and staged
|
|
|
|
|
// * Staged ---> modified and staged
|
|
|
|
|
// * Untracked ---> added but not staged
|
|
|
|
|
//
|
|
|
|
|
// Because we create the commit message, we only need to consider the staged changes
|
|
|
|
|
|
2010-10-10 16:11:01 +00:00
|
|
|
|
RepositoryStatus status = Index.Status;
|
2010-08-29 10:38:34 +00:00
|
|
|
|
|
2010-10-10 16:11:01 +00:00
|
|
|
|
string file_name = "";
|
2010-08-29 10:38:34 +00:00
|
|
|
|
string message = null;
|
|
|
|
|
|
2010-10-10 16:11:01 +00:00
|
|
|
|
if (status.Added.Count > 0) {
|
2010-08-29 10:38:34 +00:00
|
|
|
|
|
2010-10-10 16:11:01 +00:00
|
|
|
|
foreach (string added in status.Added) {
|
|
|
|
|
file_name = added;
|
|
|
|
|
break;
|
2010-08-29 10:38:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-02 10:45:10 +00:00
|
|
|
|
message = "+ ‘" + file_name + "’";
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-10-10 16:11:01 +00:00
|
|
|
|
}
|
2010-08-29 10:38:34 +00:00
|
|
|
|
|
2010-11-26 23:06:49 +00:00
|
|
|
|
if (status.Staged.Count > 0) {
|
2010-08-29 10:38:34 +00:00
|
|
|
|
|
2010-11-26 23:06:49 +00:00
|
|
|
|
foreach (string modified in status.Staged) {
|
2010-10-10 16:11:01 +00:00
|
|
|
|
file_name = modified;
|
|
|
|
|
break;
|
2010-11-26 23:06:49 +00:00
|
|
|
|
}
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-11-02 10:45:10 +00:00
|
|
|
|
message = "/ ‘" + file_name + "’";
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-10-10 16:11:01 +00:00
|
|
|
|
}
|
2010-08-29 10:38:34 +00:00
|
|
|
|
|
2010-10-10 16:11:01 +00:00
|
|
|
|
if (status.Removed.Count > 0) {
|
2010-08-29 10:38:34 +00:00
|
|
|
|
|
2010-10-10 16:11:01 +00:00
|
|
|
|
foreach (string removed in status.Removed) {
|
|
|
|
|
file_name = removed;
|
|
|
|
|
break;
|
2010-11-26 23:06:49 +00:00
|
|
|
|
}
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
2010-11-02 10:45:10 +00:00
|
|
|
|
message = "- ‘" + file_name + "’";
|
2010-10-10 16:11:01 +00:00
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-10-10 16:11:01 +00:00
|
|
|
|
int changes_count = (status.Added.Count +
|
2010-11-26 23:06:49 +00:00
|
|
|
|
status.Staged.Count +
|
2010-10-10 16:11:01 +00:00
|
|
|
|
status.Removed.Count);
|
|
|
|
|
|
|
|
|
|
if (changes_count > 1)
|
2010-11-02 10:45:10 +00:00
|
|
|
|
message += " + " + (changes_count - 1);
|
2010-08-29 10:38:34 +00:00
|
|
|
|
|
|
|
|
|
return message;
|
2010-06-20 21:05:11 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-10 22:04:08 +00:00
|
|
|
|
|
|
|
|
|
// Disposes all resourses of this object
|
|
|
|
|
new public void Dispose ()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
RemoteTimer.Dispose ();
|
|
|
|
|
LocalTimer.Dispose ();
|
|
|
|
|
Listener.Dispose ();
|
|
|
|
|
|
|
|
|
|
base.Dispose ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-20 21:05:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-07-24 12:32:05 +00:00
|
|
|
|
}
|