private void CheckForRemoteChanges() { SparkleHelpers.DebugInfo("Git", "[" + Name + "] Checking for remote changes..."); SparkleGit git = new SparkleGit(LocalPath, "ls-remote origin master"); git.Exited += delegate { if (git.ExitCode != 0) { return; } string remote_hash = git.StandardOutput.ReadToEnd(); if (!remote_hash.StartsWith(_CurrentHash)) { SparkleHelpers.DebugInfo("Git", "[" + Name + "] Remote changes found. (" + remote_hash + ")"); Fetch(); Watcher.EnableRaisingEvents = false; Rebase(); Watcher.EnableRaisingEvents = true; } }; git.Start(); git.WaitForExit(); }
public void OnAnnouncement(SparkleAnnouncement announcement) { SparkleHelpers.DebugInfo("Listener", "Got message " + announcement.Message + " from " + announcement.FolderIdentifier + " on " + Server); if (IsRecentAnnouncement(announcement)) { SparkleHelpers.DebugInfo("Listener", "Ignoring previously processed message " + announcement.Message + " from " + announcement.FolderIdentifier + " on " + Server); return; } SparkleHelpers.DebugInfo("Listener", "Processing message " + announcement.Message + " from " + announcement.FolderIdentifier + " on " + Server); AddRecentAnnouncement(announcement); this.queue_down [announcement.FolderIdentifier] = announcement; if (Received != null) { Received(announcement); } }
// Commits the made changes public void Commit(string message) { if (!AnyDifferences) { return; } SparkleGit git = new SparkleGit(LocalPath, "commit -m '" + message + "'"); git.Start(); git.WaitForExit(); _CurrentHash = GetCurrentHash(); SparkleHelpers.DebugInfo("Commit", "[" + Name + "] " + message + " (" + _CurrentHash + ")"); SparkleEventArgs args = new SparkleEventArgs("Commited") { Message = message }; if (Commited != null) { Commited(this, args); } // Collect garbage pseudo-randomly if (DateTime.Now.Second % 10 == 0) { CollectGarbage(); } }
public override bool CheckForRemoteChanges() { SparkleHelpers.DebugInfo("Git", "[" + Name + "] Checking for remote changes..."); SparkleGit git = new SparkleGit(LocalPath, "ls-remote origin master"); git.Start(); git.WaitForExit(); if (git.ExitCode != 0) { return(false); } string remote_revision = git.StandardOutput.ReadToEnd().TrimEnd(); if (!remote_revision.StartsWith(CurrentRevision)) { SparkleHelpers.DebugInfo("Git", "[" + Name + "] Remote changes found. (" + remote_revision + ")"); return(true); } else { return(false); } }
private void CheckForChanges() { lock (this.change_lock) { if (this.has_changed) { if (this.sizebuffer.Count >= 4) { this.sizebuffer.RemoveAt(0); } DirectoryInfo dir_info = new DirectoryInfo(LocalPath); this.sizebuffer.Add(CalculateSize(dir_info)); if (this.sizebuffer.Count >= 4 && this.sizebuffer [0].Equals(this.sizebuffer [1]) && this.sizebuffer [1].Equals(this.sizebuffer [2]) && this.sizebuffer [2].Equals(this.sizebuffer [3])) { SparkleHelpers.DebugInfo("Local", "[" + Name + "] Changes have settled."); this.is_buffering = false; this.has_changed = false; DisableWatching(); while (AnyDifferences) { SyncUpBase(); } EnableWatching(); } } } }
public void Announce(SparkleAnnouncement announcement) { if (!IsRecentAnnouncement(announcement)) { if (IsConnected) { SparkleHelpers.DebugInfo("Listener", "Announcing message " + announcement.Message + " to " + announcement.FolderIdentifier + " on " + Server); AnnounceInternal(announcement); AddRecentAnnouncement(announcement); } else { SparkleHelpers.DebugInfo("Listener", "Can't send message to " + Server + ". Queuing message"); this.queue_up [announcement.FolderIdentifier] = announcement; } } else { SparkleHelpers.DebugInfo("Listener", "Already processed message " + announcement.Message + " to " + announcement.FolderIdentifier + " from " + Server); } }
// Install the user's name and email and some config into // the newly cloned repository private void InstallConfiguration() { string repo_config_file_path = SparkleHelpers.CombineMore(base.target_folder, ".git", "config"); string config = String.Join(Environment.NewLine, File.ReadAllLines(repo_config_file_path)); string n = Environment.NewLine; // Show special characters in the logs config = config.Replace("[core]" + n, "[core]" + n + "quotepath = false" + n); // Be case sensitive explicitly to work on Mac config = config.Replace("ignorecase = true", "ignorecase = false"); // Ignore permission changes config = config.Replace("filemode = true", "filemode = false"); // Write the config to the file TextWriter writer = new StreamWriter(repo_config_file_path); writer.WriteLine(config); writer.Close(); SparkleHelpers.DebugInfo("Config", "Added configuration to '" + repo_config_file_path + "'"); }
// Merges the fetched changes private void Rebase() { DisableWatching(); if (AnyDifferences) { Add(); string commit_message = FormatCommitMessage(); Commit(commit_message); } SparkleGit git = new SparkleGit(LocalPath, "rebase -v FETCH_HEAD"); git.Start(); git.WaitForExit(); if (git.ExitCode != 0) { SparkleHelpers.DebugInfo("Git", "[" + Name + "] Conflict detected. Trying to get out..."); while (AnyDifferences) { ResolveConflict(); } SparkleHelpers.DebugInfo("Git", "[" + Name + "] Conflict resolved."); OnConflictResolved(); } EnableWatching(); }
private void SyncUpBase() { try { DisableWatching(); this.remote_timer.Stop(); SparkleHelpers.DebugInfo("SyncUp", "[" + Name + "] Initiated"); if (SyncStatusChanged != null) { SyncStatusChanged(SyncStatus.SyncUp); } if (SyncUp()) { SparkleHelpers.DebugInfo("SyncUp", "[" + Name + "] Done"); HasUnsyncedChanges = false; if (SyncStatusChanged != null) { SyncStatusChanged(SyncStatus.Idle); } this.listener.AnnounceBase(new SparkleAnnouncement(Identifier, CurrentRevision)); } else { SparkleHelpers.DebugInfo("SyncUp", "[" + Name + "] Error"); HasUnsyncedChanges = true; SyncDownBase(); DisableWatching(); if (this.server_online && SyncUp()) { HasUnsyncedChanges = false; if (SyncStatusChanged != null) { SyncStatusChanged(SyncStatus.Idle); } this.listener.AnnounceBase(new SparkleAnnouncement(Identifier, CurrentRevision)); } else { this.server_online = false; if (SyncStatusChanged != null) { SyncStatusChanged(SyncStatus.Error); } } } } finally { this.remote_timer.Start(); EnableWatching(); } }
// Commits the made changes new public void Commit(string message) { if (!AnyDifferences) { return; } base.Commit(message); _CurrentHash = Head.CurrentCommit.Hash; SparkleHelpers.DebugInfo("Commit", "[" + Name + "] " + message + " (" + _CurrentHash); SparkleEventArgs args = new SparkleEventArgs("Commited") { Message = message }; if (Commited != null) { Commited(this, args); } // Collect garbage pseudo-randomly if (DateTime.Now.Second % 10 == 0) { CollectGarbage(); } }
private void CheckForChanges() { lock (ChangeLock) { if (HasChanged) { if (SizeBuffer.Count >= 4) { SizeBuffer.RemoveAt(0); } DirectoryInfo dir_info = new DirectoryInfo(LocalPath); SizeBuffer.Add(CalculateFolderSize(dir_info)); if (SizeBuffer [0].Equals(SizeBuffer [1]) && SizeBuffer [1].Equals(SizeBuffer [2]) && SizeBuffer [2].Equals(SizeBuffer [3])) { SparkleHelpers.DebugInfo("Local", "[" + Name + "] Changes have settled."); _IsBuffering = false; HasChanged = false; while (AnyDifferences) { Watcher.EnableRaisingEvents = false; AddCommitAndPush(); Watcher.EnableRaisingEvents = true; } } } } }
// Install the user's name and email and some config into // the newly cloned repository private void InstallConfiguration() { string global_config_file_path = Path.Combine(SparklePaths.SparkleConfigPath, "config"); if (File.Exists(global_config_file_path)) { StreamReader reader = new StreamReader(global_config_file_path); string user_info = reader.ReadToEnd(); reader.Close(); string repo_config_file_path = SparkleHelpers.CombineMore(TargetFolder, ".git", "config"); string config = String.Join("\n", File.ReadAllLines(repo_config_file_path)); // Be case sensitive explicitly to work on Mac config = config.Replace("ignorecase = true", "ignorecase = false"); // Ignore permission changes config = config.Replace("filemode = true", "filemode = false"); // Add user info config += Environment.NewLine + user_info; TextWriter writer = new StreamWriter(repo_config_file_path); writer.WriteLine(config); writer.Close(); SparkleHelpers.DebugInfo("Config", "Added configuration to '" + repo_config_file_path + "'"); } }
// Starts a timer when something changes private void OnFileActivity(object o, FileSystemEventArgs fse_args) { if (fse_args.Name.StartsWith(".git/")) { return; } WatcherChangeTypes wct = fse_args.ChangeType; if (AnyDifferences) { _IsBuffering = true; // Only fire the event if the timer has been stopped. // This prevents multiple events from being raised whilst "buffering". if (!HasChanged) { SparkleEventArgs args = new SparkleEventArgs("ChangesDetected"); if (ChangesDetected != null) { ChangesDetected(this, args); } } SparkleHelpers.DebugInfo("Event", "[" + Name + "] " + wct.ToString() + " '" + fse_args.Name + "'"); SparkleHelpers.DebugInfo("Local", "[" + Name + "] Changes found, checking if settled."); RemoteTimer.Stop(); lock (ChangeLock) { HasChanged = true; } } }
private void EnableHostKeyCheckingForHost(string host) { string path = SparkleConfig.DefaultConfig.HomePath; if (SparkleBackend.Platform != PlatformID.Unix && SparkleBackend.Platform != PlatformID.MacOSX) { path = Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%"); } string ssh_config_file_path = SparkleHelpers.CombineMore(path, ".ssh", "config"); if (File.Exists(ssh_config_file_path)) { string current_ssh_config = File.ReadAllText(ssh_config_file_path); current_ssh_config = current_ssh_config.Trim(); string [] lines = current_ssh_config.Split('\n'); string new_ssh_config = ""; bool in_sparkleshare_section = false; foreach (string line in lines) { if (line.StartsWith("# <SparkleShare>")) { in_sparkleshare_section = true; continue; } if (line.StartsWith("# </SparkleShare>")) { in_sparkleshare_section = false; continue; } if (in_sparkleshare_section) { continue; } new_ssh_config += line + "\n"; // do not use Environment.NewLine because file is in unix format } if (string.IsNullOrEmpty(new_ssh_config.Trim())) { File.Delete(ssh_config_file_path); } else { File.WriteAllText(ssh_config_file_path, new_ssh_config.Trim()); //UnixFileSystemInfo file_info = new UnixFileInfo (ssh_config_file_path); //file_info.FileAccessPermissions = (FileAccessPermissions.UserRead | // FileAccessPermissions.UserWrite); TODO } } SparkleHelpers.DebugInfo("Fetcher", "Enabled host key checking for " + host); }
// Fetches changes from the remote repository public void Fetch() { _IsSyncing = true; _IsFetching = true; RemoteTimer.Stop(); SparkleHelpers.DebugInfo("Git", "[" + Name + "] Fetching changes..."); SparkleGit git = new SparkleGit(LocalPath, "fetch -v origin master"); SparkleEventArgs args; args = new SparkleEventArgs("FetchingStarted"); if (FetchingStarted != null) { FetchingStarted(this, args); } git.Exited += delegate { SparkleHelpers.DebugInfo("Git", "[" + Name + "] Changes fetched."); _IsSyncing = false; _IsFetching = false; _CurrentHash = Head.CurrentCommit.Hash; if (git.ExitCode != 0) { _ServerOnline = false; args = new SparkleEventArgs("FetchingFailed"); if (FetchingFailed != null) { FetchingFailed(this, args); } } else { _ServerOnline = true; args = new SparkleEventArgs("FetchingFinished"); if (FetchingFinished != null) { FetchingFinished(this, args); } } RemoteTimer.Start(); }; git.Start(); git.WaitForExit(); }
private void ConfigureSSH() { if (User.Email.Equals("Unknown")) { return; } string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal); if (!(SparkleBackend.Platform == PlatformID.Unix || SparkleBackend.Platform == PlatformID.MacOSX)) { path = Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%"); } string ssh_config_path = Path.Combine(path, ".ssh"); string ssh_config_file_path = SparkleHelpers.CombineMore(path, ".ssh", "config"); string ssh_config = "IdentityFile " + Path.Combine(SparkleConfig.ConfigPath, "sparkleshare." + User.Email + ".key"); if (!Directory.Exists(ssh_config_path)) { Directory.CreateDirectory(ssh_config_path); } if (File.Exists(ssh_config_file_path)) { string current_config = File.ReadAllText(ssh_config_file_path); if (current_config.Contains(ssh_config)) { return; } if (current_config.EndsWith("\n\n")) { ssh_config = "# SparkleShare's key\n" + ssh_config; } else if (current_config.EndsWith("\n")) { ssh_config = "\n# SparkleShare's key\n" + ssh_config; } else { ssh_config = "\n\n# SparkleShare's key\n" + ssh_config; } TextWriter writer = File.AppendText(ssh_config_file_path); writer.Write(ssh_config + "\n"); writer.Close(); } else { File.WriteAllText(ssh_config_file_path, ssh_config); } Chmod644(ssh_config_file_path); SparkleHelpers.DebugInfo("Config", "Added key to " + ssh_config_file_path); }
// Stages the made changes private void Add() { SparkleGit git = new SparkleGit(LocalPath, "add --all"); git.Start(); git.WaitForExit(); SparkleHelpers.DebugInfo("Git", "[" + Name + "] Changes staged"); }
public void OnDisconnected() { SparkleHelpers.DebugInfo("Listener", "Signal of " + Server + " lost"); if (Disconnected != null) { Disconnected(); } }
public void OnDisconnected(string message) { SparkleHelpers.DebugInfo("Listener", "Disconnected from " + Server + ": " + message); if (Disconnected != null) { Disconnected(); } }
// Removes unneeded objects private void CollectGarbage() { SparkleGit git = new SparkleGit(LocalPath, "gc"); git.Start(); git.WaitForExit(); SparkleHelpers.DebugInfo("Git", "[" + Name + "] Garbage collected."); }
private void Save() { if (!File.Exists(FullPath)) { throw new ConfigFileNotFoundException(FullPath + " does not exist"); } this.Save(FullPath); SparkleHelpers.DebugInfo("Config", "Updated \"" + FullPath + "\""); }
// Clones the remote repository public void Start() { SparkleHelpers.DebugInfo("Fetcher", "[" + this.target_folder + "] Fetching folder: " + this.remote_url); if (Started != null) { Started(); } if (Directory.Exists(this.target_folder)) { Directory.Delete(this.target_folder, true); } string host = GetHost(this.remote_url); if (String.IsNullOrEmpty(host)) { if (Failed != null) { Failed(); } return; } DisableHostKeyCheckingForHost(host); this.thread = new Thread(new ThreadStart(delegate { if (Fetch()) { SparkleHelpers.DebugInfo("Fetcher", "Finished"); EnableHostKeyCheckingForHost(host); if (Finished != null) { Finished(Warnings); } } else { SparkleHelpers.DebugInfo("Fetcher", "Failed"); EnableHostKeyCheckingForHost(host); if (Failed != null) { Failed(); } } })); this.thread.Start(); }
public void AlsoListenTo(string channel) { if (!this.channels.Contains(channel) && IsConnected) { SparkleHelpers.DebugInfo("Listener", "Subscribing to channel " + channel + " on " + Server); this.channels.Add(channel); AlsoListenToInternal(channel); } }
public SparkleConfig(string config_path, string config_file_name) { FullPath = Path.Combine(config_path, config_file_name); LogFilePath = Path.Combine(config_path, "debug.log"); if (File.Exists(LogFilePath)) { try { File.Delete(LogFilePath); } catch (Exception) { // Don't delete the debug.log if 'tail' is reading it } } if (!Directory.Exists(config_path)) { Directory.CreateDirectory(config_path); SparkleHelpers.DebugInfo("Config", "Created \"" + config_path + "\""); } string icons_path = System.IO.Path.Combine(config_path, "icons"); if (!Directory.Exists(icons_path)) { Directory.CreateDirectory(icons_path); SparkleHelpers.DebugInfo("Config", "Created \"" + icons_path + "\""); } try { Load(FullPath); } catch (TypeInitializationException) { CreateInitialConfig(); } catch (FileNotFoundException) { CreateInitialConfig(); } catch (XmlException) { FileInfo file = new FileInfo(FullPath); if (file.Length == 0) { File.Delete(FullPath); CreateInitialConfig(); } else { throw new XmlException(FullPath + " does not contain a valid config XML structure."); } } finally { Load(FullPath); TmpPath = Path.Combine(FoldersPath, ".tmp"); } }
// Merges the fetched changes public void Rebase() { if (AnyDifferences) { Add(); string commit_message = FormatCommitMessage(); Commit(commit_message); } SparkleHelpers.DebugInfo("Git", "[" + Name + "] Rebasing changes..."); SparkleGit git = new SparkleGit(LocalPath, "rebase -v FETCH_HEAD"); git.Exited += delegate { if (git.ExitCode != 0) { SparkleHelpers.DebugInfo("Git", "[" + Name + "] Conflict detected. Trying to get out..."); Watcher.EnableRaisingEvents = false; while (AnyDifferences) { ResolveConflict(); } SparkleHelpers.DebugInfo("Git", "[" + Name + "] Conflict resolved."); Watcher.EnableRaisingEvents = true; SparkleEventArgs args = new SparkleEventArgs("ConflictDetected"); if (ConflictDetected != null) { ConflictDetected(this, args); } } _CurrentHash = GetCurrentHash(); }; git.Start(); git.WaitForExit(); _CurrentHash = GetCurrentHash(); if (NewCommit != null) { NewCommit(GetCommits(1) [0], LocalPath); } SparkleHelpers.DebugInfo("Git", "[" + Name + "] Changes rebased."); }
// Starts a timer when something changes public void OnFileActivity(FileSystemEventArgs args) { // Check the watcher for the occasions where this // method is called directly if (!this.watcher.EnableRaisingEvents) { return; } string relative_path = args.FullPath.Replace(LocalPath, ""); foreach (string exclude_path in ExcludePaths) { if (relative_path.Contains(exclude_path)) { return; } } WatcherChangeTypes wct = args.ChangeType; if (AnyDifferences) { this.is_buffering = true; // We want to disable wathcing temporarily, but // not stop the local timer this.watcher.EnableRaisingEvents = false; // Only fire the event if the timer has been stopped. // This prevents multiple events from being raised whilst "buffering". if (!this.has_changed) { if (ChangesDetected != null) { ChangesDetected(); } } SparkleHelpers.DebugInfo("Event", "[" + Name + "] " + wct.ToString() + " '" + args.Name + "'"); SparkleHelpers.DebugInfo("Event", "[" + Name + "] Changes found, checking if settled."); this.remote_timer.Stop(); lock (this.change_lock) { this.has_changed = true; } } }
public override void Announce(SparkleAnnouncement announcement) { string to_send = "announce " + announcement.FolderIdentifier + " " + announcement.Message + "\n"; try { lock (this.mutex) { this.socket.Send (Encoding.UTF8.GetBytes (to_send)); } } catch (SocketException e) { SparkleHelpers.DebugInfo ("ListenerTcp", "Could not connect to " + Server + ": " + e.Message); OnDisconnected (); } }
public static SparkleListenerBase CreateListener(string folder_name, string folder_identifier) { string uri = SparkleConfig.DefaultConfig.GetFolderOptionalAttribute( folder_name, "announcements_url"); if (uri == null) { // This is SparkleShare's centralized notification service. // Don't worry, we only use this server as a backup if you // don't have your own. All data needed to connect is hashed and // we don't store any personal information ever uri = "tcp://notifications.sparkleshare.org:1986"; } Uri announce_uri = new Uri(uri); // We use only one listener per server to keep // the number of connections as low as possible foreach (SparkleListenerBase listener in listeners) { if (listener.Server.Equals(announce_uri)) { SparkleHelpers.DebugInfo("ListenerFactory", "Refered to existing listener for " + announce_uri); listener.AlsoListenTo(folder_identifier); return((SparkleListenerBase)listener); } } // Create a new listener with the appropriate // type if one doesn't exist yet for that server switch (announce_uri.Scheme) { case "tcp": listeners.Add(new SparkleListenerTcp(announce_uri, folder_identifier)); break; default: listeners.Add(new SparkleListenerTcp(announce_uri, folder_identifier)); break; } SparkleHelpers.DebugInfo("ListenerFactory", "Issued new listener for " + announce_uri); return((SparkleListenerBase)listeners [listeners.Count - 1]); }
// Stages the made changes private void Add() { SparkleHelpers.DebugInfo("Git", "[" + Name + "] Staging changes..."); SparkleGit git = new SparkleGit(LocalPath, "add --all"); git.Start(); git.WaitForExit(); SparkleHelpers.DebugInfo("Git", "[" + Name + "] Changes staged."); SparkleEventArgs args = new SparkleEventArgs("Added"); if (Added != null) { Added(this, args); } }
// Clones the remote repository public void Start() { SparkleHelpers.DebugInfo("Git", "[" + TargetFolder + "] Cloning Repository"); if (Directory.Exists(TargetFolder)) { Directory.Delete(TargetFolder, true); } if (CloningStarted != null) { CloningStarted(this, new SparkleEventArgs("CloningStarted")); } SparkleGit git = new SparkleGit(SparklePaths.SparkleTmpPath, "clone \"" + RemoteOriginUrl + "\" " + "\"" + TargetFolder + "\""); git.Exited += delegate { SparkleHelpers.DebugInfo("Git", "Exit code " + git.ExitCode.ToString()); if (git.ExitCode != 0) { SparkleHelpers.DebugInfo("Git", "[" + TargetFolder + "] Cloning failed"); if (CloningFailed != null) { CloningFailed(this, new SparkleEventArgs("CloningFailed")); } } else { InstallConfiguration(); InstallExcludeRules(); SparkleHelpers.DebugInfo("Git", "[" + TargetFolder + "] Repository cloned"); if (CloningFinished != null) { CloningFinished(this, new SparkleEventArgs("CloningFinished")); } } }; git.Start(); }