diff options
Diffstat (limited to 'SparkleLib')
-rw-r--r-- | SparkleLib/Defines.cs | 4 | ||||
-rw-r--r-- | SparkleLib/Git/Makefile.in | 39 | ||||
-rwxr-xr-x | SparkleLib/Git/SparkleFetcherGit.cs | 64 | ||||
-rw-r--r-- | SparkleLib/Git/SparkleGit.cs | 6 | ||||
-rw-r--r-- | SparkleLib/Git/SparkleRepoGit.cs | 233 | ||||
-rwxr-xr-x | SparkleLib/Makefile.am | 1 | ||||
-rw-r--r-- | SparkleLib/Makefile.in | 40 | ||||
-rwxr-xr-x | SparkleLib/SparkleConfig.cs | 14 | ||||
-rwxr-xr-x | SparkleLib/SparkleExtensions.cs | 6 | ||||
-rwxr-xr-x | SparkleLib/SparkleFetcherBase.cs | 167 | ||||
-rw-r--r-- | SparkleLib/SparkleFetcherSSH.cs | 143 | ||||
-rwxr-xr-x | SparkleLib/SparkleRepoBase.cs | 176 | ||||
-rw-r--r-- | SparkleLib/SparkleUser.cs | 4 | ||||
-rw-r--r-- | SparkleLib/SparkleWrappers.cs | 18 |
14 files changed, 456 insertions, 459 deletions
diff --git a/SparkleLib/Defines.cs b/SparkleLib/Defines.cs index 5244628..037291a 100644 --- a/SparkleLib/Defines.cs +++ b/SparkleLib/Defines.cs @@ -19,13 +19,13 @@ using System; using System.Reflection; [assembly:AssemblyTitle ("SparkleLib")] -[assembly:AssemblyVersion ("1.0.0")] +[assembly:AssemblyVersion ("1.1.0")] [assembly:AssemblyCopyright ("Copyright (c) 2010 Hylke Bons and others")] [assembly:AssemblyTrademark ("SparkleShare is a trademark of SparkleShare Ltd.")] namespace SparkleLib { public class Defines { - public const string INSTALL_DIR = "/usr/share/sparkleshare"; + public const string INSTALL_DIR = "/usr/local/share/sparkleshare"; } } diff --git a/SparkleLib/Git/Makefile.in b/SparkleLib/Git/Makefile.in index 3342f18..bcb72cd 100644 --- a/SparkleLib/Git/Makefile.in +++ b/SparkleLib/Git/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.12.4 from Makefile.am. +# Makefile.in generated by automake 1.11.3 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2012 Free Software Foundation, Inc. - +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -15,23 +16,6 @@ @SET_MAKE@ VPATH = @srcdir@ -am__make_dryrun = \ - { \ - am__dry=no; \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ - | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ - *) \ - for am__flg in $$MAKEFLAGS; do \ - case $$am__flg in \ - *=*|--*) ;; \ - *n*) am__dry=yes; break;; \ - esac; \ - done;; \ - esac; \ - test $$am__dry = yes; \ - } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -97,11 +81,6 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(moduledir)" SCRIPTS = $(module_SCRIPTS) DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ @@ -237,6 +216,7 @@ DIR_BIN = $(top_builddir)/bin # External libraries to link against, generated from configure LINK_SYSTEM = -r:System +LINK_SYSTEM_WEB = -r:System.Web LINK_MONO_POSIX = -r:Mono.Posix LINK_GLIB = $(GLIBSHARP_LIBS) LINK_GTK = $(GTKSHARP_LIBS) @@ -250,7 +230,7 @@ LINK_NOTIFY_SHARP_DEPS = $(REF_NOTIFY_SHARP) $(LINK_NOTIFY_SHARP) REF_SPARKLELIB = $(LINK_SYSTEM) $(LINK_MONO_POSIX) LINK_SPARKLELIB = -r:$(DIR_BIN)/SparkleLib.dll LINK_SPARKLELIB_DEPS = $(REF_SPARKLELIB) $(LINK_SPARKLELIB) -REF_SPARKLESHARE = $(LINK_DBUS) $(LINK_GTK) $(LINK_SPARKLELIB_DEPS) $(LINK_APP_INDICATOR) +REF_SPARKLESHARE = $(LINK_SYSTEM_WEB) $(LINK_DBUS) $(LINK_GTK) $(LINK_SPARKLELIB_DEPS) $(LINK_APP_INDICATOR) # Cute hack to replace a space with something colon := : @@ -326,11 +306,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__aclocal_m4_deps): install-moduleSCRIPTS: $(module_SCRIPTS) @$(NORMAL_INSTALL) + test -z "$(moduledir)" || $(MKDIR_P) "$(DESTDIR)$(moduledir)" @list='$(module_SCRIPTS)'; test -n "$(moduledir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(moduledir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(moduledir)" || exit 1; \ - fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ @@ -371,8 +348,6 @@ TAGS: ctags: CTAGS CTAGS: -cscope cscopelist: - distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ diff --git a/SparkleLib/Git/SparkleFetcherGit.cs b/SparkleLib/Git/SparkleFetcherGit.cs index b84e7c9..fc36646 100755 --- a/SparkleLib/Git/SparkleFetcherGit.cs +++ b/SparkleLib/Git/SparkleFetcherGit.cs @@ -12,21 +12,20 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. - - -using System; -using System.Diagnostics; -using System.IO; -using System.Text.RegularExpressions; -using System.Threading; - +// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Threading;
using SparkleLib; namespace SparkleLib.Git { - // Sets up a fetcher that can get remote folders - public class SparkleFetcher : SparkleFetcherBase { + public class SparkleFetcher : SparkleFetcherSSH { private SparkleGit git; private bool use_git_bin; @@ -62,10 +61,11 @@ namespace SparkleLib.Git { } - public SparkleFetcher (string server, string required_fingerprint, string remote_path, - string target_folder, bool fetch_prior_history) : base (server, required_fingerprint, - remote_path, target_folder, fetch_prior_history) + public SparkleFetcher (SparkleFetcherInfo info) : base (info) { + if (RemoteUrl.ToString ().StartsWith ("ssh+")) + RemoteUrl = new Uri ("ssh" + RemoteUrl.ToString ().Substring (RemoteUrl.ToString ().IndexOf ("://"))); + Uri uri = RemoteUrl; if (!uri.Scheme.Equals ("ssh") && !uri.Scheme.Equals ("https") && @@ -101,13 +101,15 @@ namespace SparkleLib.Git { this.use_git_bin = false; // TODO } - TargetFolder = target_folder; - RemoteUrl = uri; + RemoteUrl = uri; } public override bool Fetch () { + if (!base.Fetch ()) + return false; + if (FetchPriorHistory) { this.git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath, "clone --progress --no-checkout \"" + RemoteUrl + "\" \"" + TargetFolder + "\""); @@ -132,7 +134,7 @@ namespace SparkleLib.Git { double number = 0.0; if (match.Success) { - number = double.Parse (match.Groups [1].Value); + number = double.Parse (match.Groups [1].Value, new CultureInfo ("en-US")); // The cloning progress consists of two stages: the "Compressing // objects" stage which we count as 20% of the total progress, and @@ -188,8 +190,6 @@ namespace SparkleLib.Git { InstallExcludeRules (); InstallAttributeRules (); - AddWarnings (); - return true; } else { @@ -309,6 +309,7 @@ namespace SparkleLib.Git { "core.autocrlf false", // Don't change file line endings "core.precomposeunicode true", // Use the same Unicode form on all filesystems "core.safecrlf false", + "core.exludesfile \"\"", "core.packedGitLimit 128m", // Some memory limiting options "core.packedGitWindowSize 128m", "pack.deltaCacheSize 128m", @@ -330,13 +331,9 @@ namespace SparkleLib.Git { public void InstallGitBinConfiguration () { string [] settings = new string [] { - "core.bigFileThreshold 8g", + "core.bigFileThreshold 1024g", "filter.bin.clean \"git bin clean %f\"", - "filter.bin.smudge \"git bin smudge\"", - "git-bin.chunkSize 1m", - "git-bin.s3bucket \"your bucket name\"", - "git-bin.s3key \"your key\"", - "git-bin.s3secretKey \"your secret key\"" + "filter.bin.smudge \"git bin smudge\"" }; foreach (string setting in settings) { @@ -376,7 +373,7 @@ namespace SparkleLib.Git { "jpg", "jpeg", "png", "tiff", "gif", // Images "flac", "mp3", "ogg", "oga", // Audio "avi", "mov", "mpg", "mpeg", "mkv", "ogv", "ogx", "webm", // Video - "zip", "gz", "bz", "bz2", "rpm", "deb", "tgz", "rar", "ace", "7z", "pak", "tar", "iso" // Archives + "zip", "gz", "bz", "bz2", "rpm", "deb", "tgz", "rar", "ace", "7z", "pak", "tc", "iso", ".dmg" // Archives }; foreach (string extension in extensions) { @@ -390,20 +387,5 @@ namespace SparkleLib.Git { writer.Close (); } - - - private void AddWarnings () - { - if (this.warnings.Count > 0) - return; - - SparkleGit git = new SparkleGit (TargetFolder, "config --global core.excludesfile"); - string output = git.StartAndReadStandardOutput (); - - if (string.IsNullOrEmpty (output)) - return; - else - this.warnings.Add ("You seem to have a system wide ‘gitignore’ file, this may affect SparkleShare files."); - } } } diff --git a/SparkleLib/Git/SparkleGit.cs b/SparkleLib/Git/SparkleGit.cs index 3251091..3ccde01 100644 --- a/SparkleLib/Git/SparkleGit.cs +++ b/SparkleLib/Git/SparkleGit.cs @@ -83,6 +83,7 @@ namespace SparkleLib.Git { protected string LocateCommand (string name) { string [] possible_command_paths = new string [] { + Defines.INSTALL_DIR + "/bin/" + name, "/usr/bin/" + name, "/usr/local/bin/" + name, "/opt/local/bin/" + name @@ -116,6 +117,11 @@ namespace SparkleLib.Git { StartInfo.WorkingDirectory = path; StartInfo.CreateNoWindow = true; + if (StartInfo.EnvironmentVariables.ContainsKey ("LANG")) + StartInfo.EnvironmentVariables ["LANG"] = "en_US"; + else + StartInfo.EnvironmentVariables.Add ("LANG", "en_US"); + if (string.IsNullOrEmpty (ExecPath)) StartInfo.Arguments = args; else diff --git a/SparkleLib/Git/SparkleRepoGit.cs b/SparkleLib/Git/SparkleRepoGit.cs index 66aed8b..28d7ba7 100644 --- a/SparkleLib/Git/SparkleRepoGit.cs +++ b/SparkleLib/Git/SparkleRepoGit.cs @@ -12,16 +12,16 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. - - -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; - +// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
using SparkleLib; namespace SparkleLib.Git { @@ -70,8 +70,6 @@ namespace SparkleLib.Git { public SparkleRepo (string path, SparkleConfig config) : base (path, config) { - // TODO: Set git locale to en-US - SparkleGit git = new SparkleGit (LocalPath, "config core.ignorecase false"); git.StartAndWaitForExit (); @@ -81,6 +79,9 @@ namespace SparkleLib.Git { this.use_git_bin = (git.ExitCode == 0); + if (this.use_git_bin) + ConfigureGitBin (); + git = new SparkleGit (LocalPath, "config remote.origin.url \"" + RemoteUrl + "\""); git.StartAndWaitForExit (); @@ -91,6 +92,22 @@ namespace SparkleLib.Git { } + private void ConfigureGitBin () + { + SparkleGit git = new SparkleGit (LocalPath, "config filter.bin.clean \"git bin clean %f\""); + git.StartAndWaitForExit (); + + git = new SparkleGit (LocalPath, "config filter.bin.smudge \"git bin smudge\""); + git.StartAndWaitForExit (); + + git = new SparkleGit (LocalPath, "config git-bin.sftpUrl \"" + RemoteUrl + "\""); + git.StartAndWaitForExit (); + + git = new SparkleGit (LocalPath, "config git-bin.sftpPrivateKeyFile \"" + base.local_config.User.PrivateKeyFilePath + "\""); + git.StartAndWaitForExit (); + } + + public override List<string> ExcludePaths { get { List<string> rules = new List<string> (); @@ -142,30 +159,6 @@ namespace SparkleLib.Git { File.WriteAllText (size_file_path, size.ToString ()); File.WriteAllText (history_size_file_path, history_size.ToString ()); } - - - public override string [] UnsyncedFilePaths { - get { - List<string> file_paths = new List<string> (); - SparkleGit git = new SparkleGit (LocalPath, "status --porcelain"); - string output = git.StartAndReadStandardOutput (); - string [] lines = output.Split ("\n".ToCharArray ()); - - foreach (string line in lines) { - if (line [1].ToString ().Equals ("M") || - line [1].ToString ().Equals ("?") || - line [1].ToString ().Equals ("A")) { - - string path = line.Substring (3); - path = path.Trim ("\"".ToCharArray ()); - - file_paths.Add (path); - } - } - - return file_paths.ToArray (); - } - } public override string CurrentRevision { @@ -192,34 +185,43 @@ namespace SparkleLib.Git { if (git.ExitCode != 0) return false; - string remote_revision = output.Substring (0, 40); + string remote_revision = "" + output.Substring (0, 40); - if (!string.IsNullOrEmpty (remote_revision) && !remote_revision.StartsWith (current_revision)) { - SparkleLogger.LogInfo ("Git", Name + " | Remote changes found, local: " + - current_revision + ", remote: " + remote_revision); + if (!remote_revision.Equals (current_revision)) { + git = new SparkleGit (LocalPath, "merge-base " + remote_revision + " master"); + git.StartAndWaitForExit (); - Error = ErrorStatus.None; - return true; + if (git.ExitCode != 0) { + SparkleLogger.LogInfo ("Git", Name + " | Remote changes found, local: " + + current_revision + ", remote: " + remote_revision); - } else { - SparkleLogger.LogInfo ("Git", Name + " | No remote changes, local+remote: " + current_revision); - return false; - } + Error = ErrorStatus.None; + return true; + + } else { + SparkleLogger.LogInfo ("Git", Name + " | Remote " + remote_revision + " is already in our history"); + return false; + } + } + + SparkleLogger.LogInfo ("Git", Name + " | No remote changes, local+remote: " + current_revision); + return false; } } public override bool SyncUp () { - if (HasLocalChanges) { - Add (); - - string message = FormatCommitMessage (); - Commit (message); + if (!Add ()) { + Error = ErrorStatus.UnreadableFiles; + return false; } - SparkleGit git; + string message = FormatCommitMessage (); + if (message != null) + Commit (message); + if (this.use_git_bin) { SparkleGitBin git_bin = new SparkleGitBin (LocalPath, "push"); git_bin.StartAndWaitForExit (); @@ -227,8 +229,7 @@ namespace SparkleLib.Git { // TODO: Progress } - git = new SparkleGit (LocalPath, "push --progress \"" + RemoteUrl + "\" " + this.branch); - + SparkleGit git = new SparkleGit (LocalPath, "push --progress \"" + RemoteUrl + "\" " + this.branch); git.StartInfo.RedirectStandardError = true; git.Start (); @@ -241,7 +242,12 @@ namespace SparkleLib.Git { double number = 0.0; if (match.Success) { - number = double.Parse (match.Groups [1].Value); + try { + number = double.Parse (match.Groups [1].Value, new CultureInfo ("en-US")); + + } catch (FormatException) { + SparkleLogger.LogInfo ("Git", "Error parsing progress: \"" + match.Groups [1] + "\""); + } // The pushing progress consists of two stages: the "Compressing // objects" stage which we count as 20% of the total progress, and @@ -256,7 +262,12 @@ namespace SparkleLib.Git { Match speed_match = this.speed_regex.Match (line); if (speed_match.Success) { - speed = double.Parse (speed_match.Groups [1].Value) * 1024; + try { + speed = double.Parse (speed_match.Groups [1].Value, new CultureInfo ("en-US")) * 1024; + + } catch (FormatException) { + SparkleLogger.LogInfo ("Git", "Error parsing speed: \"" + speed_match.Groups [1] + "\""); + } if (speed_match.Groups [2].Value.Equals ("M")) speed = speed * 1024; @@ -323,7 +334,12 @@ namespace SparkleLib.Git { double number = 0.0; if (match.Success) { - number = double.Parse (match.Groups [1].Value); + try { + number = double.Parse (match.Groups [1].Value, new CultureInfo ("en-US")); + + } catch (FormatException) { + SparkleLogger.LogInfo ("Git", "Error parsing progress: \"" + match.Groups [1] + "\""); + } // The fetching progress consists of two stages: the "Compressing // objects" stage which we count as 20% of the total progress, and @@ -338,7 +354,12 @@ namespace SparkleLib.Git { Match speed_match = this.speed_regex.Match (line); if (speed_match.Success) { - speed = double.Parse (speed_match.Groups [1].Value) * 1024; + try { + speed = double.Parse (speed_match.Groups [1].Value, new CultureInfo ("en-US")) * 1024; + + } catch (FormatException) { + SparkleLogger.LogInfo ("Git", "Error parsing speed: \"" + speed_match.Groups [1] + "\""); + } if (speed_match.Groups [2].Value.Equals ("M")) speed = speed * 1024; @@ -408,10 +429,12 @@ namespace SparkleLib.Git { // Stages the made changes - private void Add () + private bool Add () { SparkleGit git = new SparkleGit (LocalPath, "add --all"); git.StartAndWaitForExit (); + + return (git.ExitCode == 0); } @@ -440,16 +463,27 @@ namespace SparkleLib.Git { // Merges the fetched changes private bool Rebase () { - if (HasLocalChanges) { + string message = FormatCommitMessage (); + + if (message != null) { Add (); + Commit (message); + } - string commit_message = FormatCommitMessage (); - Commit (commit_message); + SparkleGit git; + string rebase_apply_path = new string [] { LocalPath, ".git", "rebase-apply" }.Combine (); + + // Stop if we're already in a rebase because something went wrong + if (Directory.Exists (rebase_apply_path)) { + git = new SparkleGit (LocalPath, "rebase --abort"); + git.StartAndWaitForExit (); + + return false; } // Temporarily change the ignorecase setting to true to avoid - // conflicts in file names due to case changes - SparkleGit git = new SparkleGit (LocalPath, "config core.ignorecase true"); + // conflicts in file names due to letter case changes + git = new SparkleGit (LocalPath, "config core.ignorecase true"); git.StartAndWaitForExit (); git = new SparkleGit (LocalPath, "rebase FETCH_HEAD"); @@ -461,7 +495,7 @@ namespace SparkleLib.Git { // Stop when we can't rebase due to locked local files // error: cannot stat 'filename': Permission denied if (error_output.Contains ("error: cannot stat")) { - Error = ErrorStatus.LockedFiles; + Error = ErrorStatus.UnreadableFiles; SparkleLogger.LogInfo ("Git", Name + " | Error status changed to " + Error); git = new SparkleGit (LocalPath, "rebase --abort"); @@ -474,7 +508,6 @@ namespace SparkleLib.Git { } else { SparkleLogger.LogInfo ("Git", Name + " | Conflict detected, trying to get out..."); - string rebase_apply_path = new string [] { LocalPath, ".git", "rebase-apply" }.Combine (); while (Directory.Exists (rebase_apply_path) && HasLocalChanges) { try { @@ -705,6 +738,13 @@ namespace SparkleLib.Git { string output = git.StartAndReadStandardOutput (); + if (path == null && string.IsNullOrWhiteSpace (output)) { + git = new SparkleGit (LocalPath, "log -n 75 --raw --find-renames --date=iso " + + "--format=medium --no-color --no-merges"); + + output = git.StartAndReadStandardOutput (); + } + string [] lines = output.Split ("\n".ToCharArray ()); List<string> entries = new List <string> (); @@ -759,6 +799,9 @@ namespace SparkleLib.Git { foreach (string entry_line in entry_lines) { if (entry_line.StartsWith (":")) { + if (entry_line.Contains ("\\177")) + continue; + string type_letter = entry_line [37].ToString (); string file_path = entry_line.Substring (39); bool change_is_folder = false; @@ -852,18 +895,18 @@ namespace SparkleLib.Git { } else { if (path != null) { - bool skip_change_set = false;; + List<SparkleChange> changes_to_skip = new List<SparkleChange> (); foreach (SparkleChange change in change_set.Changes) { - if ((change.Type == SparkleChangeType.Deleted || - change.Type == SparkleChangeType.Moved) && change.Path.Equals (path)) { + if ((change.Type == SparkleChangeType.Deleted || change.Type == SparkleChangeType.Moved) + && change.Path.Equals (path)) { - skip_change_set = true; + changes_to_skip.Add (change); } } - if (skip_change_set) - continue; + foreach (SparkleChange change_to_skip in changes_to_skip) + change_set.Changes.Remove (change_to_skip); } change_sets.Add (change_set); @@ -984,6 +1027,7 @@ namespace SparkleLib.Git { while (!git_status.StandardOutput.EndOfStream) { string line = git_status.StandardOutput.ReadLine (); + line = line.Trim (); if (line.EndsWith (".empty") || line.EndsWith (".empty\"")) line = line.Replace (".empty", ""); @@ -1020,42 +1064,47 @@ namespace SparkleLib.Git { git_status.StandardOutput.ReadToEnd (); git_status.WaitForExit (); - return message; + if (string.IsNullOrWhiteSpace (message)) + return null; + else + return message; } // Recursively gets a folder's size in bytes - private double CalculateSizes (DirectoryInfo parent) + private long CalculateSizes (DirectoryInfo parent) { - if (!Directory.Exists (parent.FullName) || parent.Name.Equals ("rebase-apply")) - return 0; - - double size = 0; + long size = 0; try { - foreach (FileInfo file in parent.GetFiles ()) { - if (!file.Exists) - return 0; + foreach (DirectoryInfo directory in parent.GetDirectories ()) { + if (directory.IsSymlink () || + directory.Name.Equals (".git") || + directory.Name.Equals ("rebase-apply")) { - if (file.Name.Equals (".empty")) - File.SetAttributes (file.FullName, FileAttributes.Hidden); + continue; + } - size += file.Length; + size += CalculateSizes (directory); } } catch (Exception e) { - SparkleLogger.LogInfo ("Local", "Error calculating size", e); - return 0; + SparkleLogger.LogInfo ("Local", "Error calculating directory size", e); } - try { - foreach (DirectoryInfo directory in parent.GetDirectories ()) - size += CalculateSizes (directory); - + foreach (FileInfo file in parent.GetFiles ()) { + if (file.IsSymlink ()) + continue; + + if (file.Name.Equals (".empty")) + File.SetAttributes (file.FullName, FileAttributes.Hidden); + else + size += file.Length; + } + } catch (Exception e) { - SparkleLogger.LogInfo ("Local", "Error calculating size", e); - return 0; + SparkleLogger.LogInfo ("Local", "Error calculating file size", e); } return size; diff --git a/SparkleLib/Makefile.am b/SparkleLib/Makefile.am index da03327..55fad6c 100755 --- a/SparkleLib/Makefile.am +++ b/SparkleLib/Makefile.am @@ -9,6 +9,7 @@ SOURCES = \ SparkleConfig.cs \ SparkleExtensions.cs \ SparkleFetcherBase.cs \ + SparkleFetcherSSH.cs \ SparkleListenerBase.cs \ SparkleListenerFactory.cs \ SparkleListenerTcp.cs \ diff --git a/SparkleLib/Makefile.in b/SparkleLib/Makefile.in index e6e6afc..e5b5c6c 100644 --- a/SparkleLib/Makefile.in +++ b/SparkleLib/Makefile.in @@ -1,8 +1,9 @@ -# Makefile.in generated by automake 1.12.4 from Makefile.am. +# Makefile.in generated by automake 1.11.3 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2012 Free Software Foundation, Inc. - +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -15,23 +16,6 @@ @SET_MAKE@ VPATH = @srcdir@ -am__make_dryrun = \ - { \ - am__dry=no; \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ - | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ - *) \ - for am__flg in $$MAKEFLAGS; do \ - case $$am__flg in \ - *=*|--*) ;; \ - *n*) am__dry=yes; break;; \ - esac; \ - done;; \ - esac; \ - test $$am__dry = yes; \ - } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ @@ -97,11 +81,6 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(moduledir)" SCRIPTS = $(module_SCRIPTS) DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ @@ -226,6 +205,7 @@ SOURCES = \ SparkleConfig.cs \ SparkleExtensions.cs \ SparkleFetcherBase.cs \ + SparkleFetcherSSH.cs \ SparkleListenerBase.cs \ SparkleListenerFactory.cs \ SparkleListenerTcp.cs \ @@ -245,6 +225,7 @@ DIR_BIN = $(top_builddir)/bin # External libraries to link against, generated from configure LINK_SYSTEM = -r:System +LINK_SYSTEM_WEB = -r:System.Web LINK_MONO_POSIX = -r:Mono.Posix LINK_GLIB = $(GLIBSHARP_LIBS) LINK_GTK = $(GTKSHARP_LIBS) @@ -258,7 +239,7 @@ LINK_NOTIFY_SHARP_DEPS = $(REF_NOTIFY_SHARP) $(LINK_NOTIFY_SHARP) REF_SPARKLELIB = $(LINK_SYSTEM) $(LINK_MONO_POSIX) LINK_SPARKLELIB = -r:$(DIR_BIN)/SparkleLib.dll LINK_SPARKLELIB_DEPS = $(REF_SPARKLELIB) $(LINK_SPARKLELIB) -REF_SPARKLESHARE = $(LINK_DBUS) $(LINK_GTK) $(LINK_SPARKLELIB_DEPS) $(LINK_APP_INDICATOR) +REF_SPARKLESHARE = $(LINK_SYSTEM_WEB) $(LINK_DBUS) $(LINK_GTK) $(LINK_SPARKLELIB_DEPS) $(LINK_APP_INDICATOR) # Cute hack to replace a space with something colon := : @@ -337,11 +318,8 @@ Defines.cs: $(top_builddir)/config.status $(srcdir)/Defines.cs.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-moduleSCRIPTS: $(module_SCRIPTS) @$(NORMAL_INSTALL) + test -z "$(moduledir)" || $(MKDIR_P) "$(DESTDIR)$(moduledir)" @list='$(module_SCRIPTS)'; test -n "$(moduledir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(moduledir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(moduledir)" || exit 1; \ - fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ @@ -382,8 +360,6 @@ TAGS: ctags: CTAGS CTAGS: -cscope cscopelist: - distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ diff --git a/SparkleLib/SparkleConfig.cs b/SparkleLib/SparkleConfig.cs index fdc34b9..03404a2 100755 --- a/SparkleLib/SparkleConfig.cs +++ b/SparkleLib/SparkleConfig.cs @@ -136,11 +136,17 @@ namespace SparkleLib { string user_name = name_node.Value; string user_email = email_node.Value; - SparkleUser user = new SparkleUser (user_name, user_email); - string [] pubkey_file_paths = Directory.GetFiles (Path.GetDirectoryName (FullPath), "*.pub"); + SparkleUser user = new SparkleUser (user_name, user_email); - if (pubkey_file_paths.Length > 0) - user.PublicKey = File.ReadAllText (pubkey_file_paths [0]); + string [] private_key_file_paths = Directory.GetFiles (Path.GetDirectoryName (FullPath), "*.key"); + + if (private_key_file_paths.Length > 0) { + user.PrivateKey = File.ReadAllText (private_key_file_paths [0]); + user.PrivateKeyFilePath = private_key_file_paths [0]; + + user.PublicKey = File.ReadAllText (private_key_file_paths [0] + ".pub"); + user.PublicKeyFilePath = private_key_file_paths [0] + ".pub"; + } return user; } diff --git a/SparkleLib/SparkleExtensions.cs b/SparkleLib/SparkleExtensions.cs index fb39aa7..ef6dd97 100755 --- a/SparkleLib/SparkleExtensions.cs +++ b/SparkleLib/SparkleExtensions.cs @@ -70,5 +70,11 @@ namespace SparkleLib { else return byte_count.ToString () + " ʙ"; } + + + public static bool IsSymlink (this FileSystemInfo file) + { + return ((file.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint); + } } } diff --git a/SparkleLib/SparkleFetcherBase.cs b/SparkleLib/SparkleFetcherBase.cs index 3f08c3b..6c57599 100755 --- a/SparkleLib/SparkleFetcherBase.cs +++ b/SparkleLib/SparkleFetcherBase.cs @@ -24,7 +24,16 @@ using System.Threading; namespace SparkleLib { - // Sets up a fetcher that can get remote folders + public class SparkleFetcherInfo { + public string Address; + public string Fingerprint; + public string RemotePath; + public string TargetDirectory; + public string AnnouncementsUrl; + public bool FetchPriorHistory; + } + + public abstract class SparkleFetcherBase { public event Action Started = delegate { }; @@ -49,6 +58,7 @@ namespace SparkleLib { public string TargetFolder { get; protected set; } public bool IsActive { get; private set; } public string Identifier; + public SparkleFetcherInfo OriginalFetcherInfo; public string [] Warnings { get { @@ -73,7 +83,7 @@ namespace SparkleLib { "*.part", "*.crdownload", // Firefox and Chromium temporary download files ".*.sw[a-z]", "*.un~", "*.swp", "*.swo", // vi(m) ".directory", // KDE - ".DS_Store", "Icon\r\r", "._*", ".Spotlight-V100", ".Trashes", // Mac OS X + ".DS_Store", "Icon\r", "._*", ".Spotlight-V100", ".Trashes", // Mac OS X "*(Autosaved).graffle", // Omnigraffle "Thumbs.db", "Desktop.ini", // Windows "~*.tmp", "~*.TMP", "*~*.tmp", "*~*.TMP", // MS Office @@ -83,32 +93,36 @@ namespace SparkleLib { "*/CVS/*", ".cvsignore", "*/.cvsignore", // CVS "/.svn/*", "*/.svn/*", // Subversion "/.hg/*", "*/.hg/*", "*/.hgignore", // Mercurial - "/.bzr/*", "*/.bzr/*", "*/.bzrignore" // Bazaar + "/.bzr/*", "*/.bzr/*", "*/.bzrignore", // Bazaar + "*<*", "*>*", "*:*", "*\"*", "*|*", "*\\?*", "*\\**", "*\\\\*" // Not allowed on Windows systems, + // see (http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx) }; private Thread thread; - public SparkleFetcherBase (string server, string required_fingerprint, - string remote_path, string target_folder, bool fetch_prior_history) + public SparkleFetcherBase (SparkleFetcherInfo info) { - RequiredFingerprint = required_fingerprint; - FetchPriorHistory = fetch_prior_history; - remote_path = remote_path.Trim ("/".ToCharArray ()); + OriginalFetcherInfo = info; + RequiredFingerprint = info.Fingerprint; + FetchPriorHistory = info.FetchPriorHistory; + string remote_path = info.RemotePath.Trim ("/".ToCharArray ()); + string address = info.Address; - if (server.EndsWith ("/")) - server = server.Substring (0, server.Length - 1); + if (address.EndsWith ("/")) + address = address.Substring (0, address.Length - 1); if (!remote_path.StartsWith ("/")) remote_path = "/" + remote_path; - if (!server.Contains ("://")) - server = "ssh://" + server; + if (!address.Contains ("://")) + address = "ssh://" + address; - TargetFolder = target_folder; - RemoteUrl = new Uri (server + remote_path); - IsActive = false; + TargetFolder = info.TargetDirectory; + + RemoteUrl = new Uri (address + remote_path); + IsActive = false; } @@ -119,44 +133,9 @@ namespace SparkleLib { SparkleLogger.LogInfo ("Fetcher", TargetFolder + " | Fetching folder: " + RemoteUrl); - if (Directory.Exists (TargetFolder)) + if (Directory.Exists (TargetFolder)) Directory.Delete (TargetFolder, true); - string host_key = ""; - - if (!RemoteUrl.Scheme.StartsWith ("http")) { - host_key = FetchHostKey (); - - if (string.IsNullOrEmpty (RemoteUrl.Host) || host_key == null) { - SparkleLogger.LogInfo ("Auth", "Could not fetch host key"); - Failed (); - - return; - } - - bool warn = true; - if (RequiredFingerprint != null) { - string host_fingerprint = DeriveFingerprint (host_key); - - if (host_fingerprint == null || !RequiredFingerprint.Equals (host_fingerprint)) { - SparkleLogger.LogInfo ("Auth", "Fingerprint doesn't match"); - - this.errors.Add ("error: Host fingerprint doesn't match"); - Failed (); - - return; - } - - warn = false; - SparkleLogger.LogInfo ("Auth", "Fingerprint matches"); - - } else { - SparkleLogger.LogInfo ("Auth", "Skipping fingerprint check"); - } - - AcceptHostKey (host_key, warn); - } - this.thread = new Thread (() => { if (Fetch ()) { Thread.Sleep (500); @@ -209,7 +188,7 @@ namespace SparkleLib { UriBuilder uri_builder = new UriBuilder (RemoteUrl); - if (RemoteUrl.Scheme.StartsWith ("http")) { + if (RemoteUrl.Scheme.Contains ("http")) { uri_builder.UserName = ""; uri_builder.Password = ""; } @@ -233,8 +212,7 @@ namespace SparkleLib { public static string CreateIdentifier () { - string random = Path.GetRandomFileName (); - return random.SHA1 (); + return Path.GetRandomFileName ().SHA1 (); } @@ -257,87 +235,6 @@ namespace SparkleLib { } - private string FetchHostKey () - { - SparkleLogger.LogInfo ("Auth", "Fetching host key for " + RemoteUrl.Host); - - Process process = new Process (); - process.StartInfo.FileName = "ssh-keyscan"; - process.StartInfo.WorkingDirectory = SparkleConfig.DefaultConfig.TmpPath; - process.StartInfo.UseShellExecute = false; - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.CreateNoWindow = true; - process.EnableRaisingEvents = true; - - if (RemoteUrl.Port < 1) - process.StartInfo.Arguments = "-t rsa -p 22 " + RemoteUrl.Host; - else - process.StartInfo.Arguments = "-t rsa -p " + RemoteUrl.Port + " " + RemoteUrl.Host; - - SparkleLogger.LogInfo ("Cmd", process.StartInfo.FileName + " " + process.StartInfo.Arguments); - - process.Start (); - string host_key = process.StandardOutput.ReadToEnd ().Trim (); - process.WaitForExit (); - - if (process.ExitCode == 0 && !string.IsNullOrEmpty (host_key)) - return host_key; - else - return null; - } - - - private string DeriveFingerprint (string public_key) - { - try { - MD5 md5 = new MD5CryptoServiceProvider (); - string key = public_key.Split (" ".ToCharArray ()) [2]; - byte [] b64_bytes = Convert.FromBase64String (key); - byte [] md5_bytes = md5.ComputeHash (b64_bytes); - string fingerprint = BitConverter.ToString (md5_bytes); - - return fingerprint.ToLower ().Replace ("-", ":"); - - } catch (Exception e) { - SparkleLogger.LogInfo ("Fetcher", "Failed creating fingerprint: " + e.Message + " " + e.StackTrace); - return null; - } - } - - - private void AcceptHostKey (string host_key, bool warn) - { - string ssh_config_path = Path.Combine (SparkleConfig.DefaultConfig.HomePath, ".ssh"); - string known_hosts_file_path = Path.Combine (ssh_config_path, "known_hosts"); - - if (!File.Exists (known_hosts_file_path)) { - if (!Directory.Exists (ssh_config_path)) - Directory.CreateDirectory (ssh_config_path); - - File.Create (known_hosts_file_path).Close (); - } - - string host = RemoteUrl.Host; - string known_hosts = File.ReadAllText (known_hosts_file_path); - string [] known_hosts_lines = File.ReadAllLines (known_hosts_file_path); - - foreach (string line in known_hosts_lines) { - if (line.StartsWith (host + " ")) - return; - } - - if (known_hosts.EndsWith ("\n")) - File.AppendAllText (known_hosts_file_path, host_key + "\n"); - else - File.AppendAllText (known_hosts_file_path, "\n" + host_key + "\n"); - - SparkleLogger.LogInfo ("Auth", "Accepted host key for " + host); - - if (warn) - this.warnings.Add ("The following host key has been accepted:\n" + DeriveFingerprint (host_key)); - } - - public static string GetBackend (string address) { if (address.StartsWith ("ssh+")) { diff --git a/SparkleLib/SparkleFetcherSSH.cs b/SparkleLib/SparkleFetcherSSH.cs new file mode 100644 index 0000000..d55a9de --- /dev/null +++ b/SparkleLib/SparkleFetcherSSH.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Security.Cryptography; +using System.Threading; + +namespace SparkleLib { + + public abstract class SparkleFetcherSSH : SparkleFetcherBase { + + public SparkleFetcherSSH (SparkleFetcherInfo info) : base (info) + { + } + + + public override bool Fetch () + { + if (RemoteUrl.Host.EndsWith(".onion")) { + // Tor has special domain names called ".onion addresses". They can only be + // resolved by using a proxy via tor. While the rest of the openssh suite + // fully supports proxying, ssh-keyscan does not, so we can't use it for .onion + SparkleLogger.LogInfo ("Auth", "using tor .onion address skipping ssh-keyscan"); + } else if (!RemoteUrl.Scheme.StartsWith ("http")) { + string host_key = FetchHostKey (); + + if (string.IsNullOrEmpty (RemoteUrl.Host) || host_key == null) { + SparkleLogger.LogInfo ("Auth", "Could not fetch host key"); + this.errors.Add ("error: Could not fetch host key"); + + return false; + } + + bool warn = true; + if (RequiredFingerprint != null) { + string host_fingerprint = DeriveFingerprint (host_key); + + if (host_fingerprint == null || !RequiredFingerprint.Equals (host_fingerprint)) { + SparkleLogger.LogInfo ("Auth", "Fingerprint doesn't match"); + this.errors.Add ("error: Host fingerprint doesn't match"); + + return false; + } + + warn = false; + SparkleLogger.LogInfo ("Auth", "Fingerprint matches"); + + } else { + SparkleLogger.LogInfo ("Auth", "Skipping fingerprint check"); + } + + AcceptHostKey (host_key, warn); + } + + return true; + } + + + private string FetchHostKey () + { + SparkleLogger.LogInfo ("Auth", "Fetching host key for " + RemoteUrl.Host); + + Process process = new Process (); + process.StartInfo.FileName = "ssh-keyscan"; + process.StartInfo.WorkingDirectory = SparkleConfig.DefaultConfig.TmpPath; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.CreateNoWindow = true; + process.EnableRaisingEvents = true; + + string [] key_types = {"rsa", "dsa", "ecdsa"}; + + foreach (string key_type in key_types) { + if (RemoteUrl.Port < 1) + process.StartInfo.Arguments = "-t " + key_type + " -p 22 " + RemoteUrl.Host; + else + process.StartInfo.Arguments = "-t " + key_type + " -p " + RemoteUrl.Port + " " + RemoteUrl.Host; + + SparkleLogger.LogInfo ("Cmd", process.StartInfo.FileName + " " + process.StartInfo.Arguments); + + process.Start (); + string host_key = process.StandardOutput.ReadToEnd ().Trim (); + process.WaitForExit (); + + if (process.ExitCode == 0 && !string.IsNullOrWhiteSpace (host_key)) + return host_key; + } + + return null; + } + + + private string DeriveFingerprint (string public_key) + { + try { + MD5 md5 = new MD5CryptoServiceProvider (); + string key = public_key.Split (" ".ToCharArray ()) [2]; + byte [] b64_bytes = Convert.FromBase64String (key); + byte [] md5_bytes = md5.ComputeHash (b64_bytes); + string fingerprint = BitConverter.ToString (md5_bytes); + + return fingerprint.ToLower ().Replace ("-", ":"); + + } catch (Exception e) { + SparkleLogger.LogInfo ("Fetcher", "Failed creating fingerprint: " + e.Message + " " + e.StackTrace); + return null; + } + } + + + private void AcceptHostKey (string host_key, bool warn) + { + string ssh_config_path = Path.Combine (SparkleConfig.DefaultConfig.HomePath, ".ssh"); + string known_hosts_file_path = Path.Combine (ssh_config_path, "known_hosts"); + + if (!File.Exists (known_hosts_file_path)) { + if (!Directory.Exists (ssh_config_path)) + Directory.CreateDirectory (ssh_config_path); + + File.Create (known_hosts_file_path).Close (); + } + + string host = RemoteUrl.Host; + string known_hosts = File.ReadAllText (known_hosts_file_path); + string [] known_hosts_lines = File.ReadAllLines (known_hosts_file_path); + + foreach (string line in known_hosts_lines) { + if (line.StartsWith (host + " ")) + return; + } + + if (known_hosts.EndsWith ("\n")) + File.AppendAllText (known_hosts_file_path, host_key + "\n"); + else + File.AppendAllText (known_hosts_file_path, "\n" + host_key + "\n"); + + SparkleLogger.LogInfo ("Auth", "Accepted host key for " + host); + + if (warn) + this.warnings.Add ("The following host key has been accepted:\n" + DeriveFingerprint (host_key)); + } + } +} diff --git a/SparkleLib/SparkleRepoBase.cs b/SparkleLib/SparkleRepoBase.cs index 1a87d37..9a7b91d 100755 --- a/SparkleLib/SparkleRepoBase.cs +++ b/SparkleLib/SparkleRepoBase.cs @@ -38,27 +38,32 @@ namespace SparkleLib { HostIdentityChanged, AuthenticationFailed, DiskSpaceExceeded, - LockedFiles, + UnreadableFiles, NotFound } public abstract class SparkleRepoBase { - public static bool UseCustomWatcher = false; + + public abstract bool SyncUp (); + public abstract bool SyncDown (); + public abstract void RestoreFile (string path, string revision, string target_file_path); + public abstract bool HasUnsyncedChanges { get; set; } + public abstract bool HasLocalChanges { get; } + public abstract bool HasRemoteChanges { get; } public abstract string CurrentRevision { get; } public abstract double Size { get; } public abstract double HistorySize { get; } + public abstract List<string> ExcludePaths { get; } - public abstract bool HasUnsyncedChanges { get; set; } - public abstract bool HasLocalChanges { get; } - public abstract bool HasRemoteChanges { get; } - public abstract bool SyncUp (); - public abstract bool SyncDown (); public abstract List<SparkleChangeSet> GetChangeSets (); public abstract List<SparkleChangeSet> GetChangeSets (string path); - public abstract void RestoreFile (string path, string revision, string target_file_path); + + + public static bool UseCustomWatcher = false; + public event SyncStatusChangedEventHandler SyncStatusChanged = delegate { }; public delegate void SyncStatusChangedEventHandler (SyncStatus new_status); @@ -83,7 +88,7 @@ namespace SparkleLib { public double ProgressPercentage { get; private set; } public double ProgressSpeed { get; private set; } - public string Identifier { + public virtual string Identifier { get { if (this.identifier != null) return this.identifier; @@ -114,12 +119,6 @@ namespace SparkleLib { } } - public virtual string [] UnsyncedFilePaths { - get { - return new string [0]; - } - } - protected SparkleConfig local_config; @@ -127,16 +126,13 @@ namespace SparkleLib { private string identifier; private SparkleListenerBase listener; private SparkleWatcher watcher; - private TimeSpan poll_interval = PollInterval.Short; - private DateTime last_poll = DateTime.Now; - private DateTime progress_last_change = DateTime.Now; - private TimeSpan progress_change_interval = new TimeSpan (0, 0, 0, 1); - private Timers.Timer remote_timer = new Timers.Timer () { Interval = 5000 }; + private TimeSpan poll_interval = PollInterval.Short; + private DateTime last_poll = DateTime.Now; + private DateTime progress_last_change = DateTime.Now; + private Timers.Timer remote_timer = new Timers.Timer () { Interval = 5000 }; private bool is_syncing { - get { - return (Status == SyncStatus.SyncUp || Status == SyncStatus.SyncDown || IsBuffering); - } + get { return (Status == SyncStatus.SyncUp || Status == SyncStatus.SyncDown || IsBuffering); } } private static class PollInterval { @@ -162,9 +158,7 @@ namespace SparkleLib { string identifier_file_path = Path.Combine (LocalPath, ".sparkleshare"); File.SetAttributes (identifier_file_path, FileAttributes.Hidden); - SyncStatusChanged += delegate (SyncStatus status) { - Status = status; - }; + SyncStatusChanged += delegate (SyncStatus status) { Status = status; }; if (!UseCustomWatcher) this.watcher = new SparkleWatcher (LocalPath); @@ -176,20 +170,23 @@ namespace SparkleLib { return; int time_comparison = DateTime.Compare (this.last_poll, DateTime.Now.Subtract (this.poll_interval)); - bool time_to_poll = (time_comparison < 0); - if (time_to_poll && !is_syncing) { + if (time_comparison < 0) { + if (HasUnsyncedChanges && !this.is_syncing) + SyncUpBase (); + this.last_poll = DateTime.Now; - if (HasRemoteChanges) { - this.poll_interval = PollInterval.Long; + if (HasRemoteChanges && !this.is_syncing) SyncDownBase (); - } + + if (this.listener.IsConnected) + this.poll_interval = PollInterval.Long; } // In the unlikely case that we haven't synced up our // changes or the server was down, sync up again - if (HasUnsyncedChanges && !is_syncing && Error == ErrorStatus.None) + if (HasUnsyncedChanges && !this.is_syncing && Error == ErrorStatus.None) SyncUpBase (); }; } @@ -197,18 +194,20 @@ namespace SparkleLib { public void Initialize () { - if (!UseCustomWatcher) - this.watcher.ChangeEvent += OnFileActivity; - - // Sync up everything that changed - // since we've been offline + // Sync up everything that changed since we've been offline new Thread (() => { - if (!this.is_syncing && (HasLocalChanges || HasUnsyncedChanges)) { - SyncUpBase (); + if (HasRemoteChanges) + SyncDownBase (); - while (HasLocalChanges && !this.is_syncing) + if (HasUnsyncedChanges || HasLocalChanges) { + do { SyncUpBase (); + + } while (HasLocalChanges); } + + if (!UseCustomWatcher) + this.watcher.ChangeEvent += OnFileActivity; this.remote_timer.Start (); @@ -245,12 +244,12 @@ namespace SparkleLib { SparkleLogger.LogInfo ("Local", Name + " | Activity detected, waiting for it to settle..."); List<double> size_buffer = new List<double> (); + DirectoryInfo info = new DirectoryInfo (LocalPath); do { if (size_buffer.Count >= 4) size_buffer.RemoveAt (0); - DirectoryInfo info = new DirectoryInfo (LocalPath); size_buffer.Add (CalculateSize (info)); if (size_buffer.Count >= 4 && @@ -265,6 +264,9 @@ namespace SparkleLib { do { SyncUpBase (); + if (Error == ErrorStatus.UnreadableFiles) + return; + } while (HasLocalChanges); } else { @@ -286,11 +288,8 @@ namespace SparkleLib { { if (Error == ErrorStatus.None || this.is_syncing) return; - - if (Error == ErrorStatus.LockedFiles) - SyncDownBase (); - else - SyncUpBase (); + + SyncUpBase (); } @@ -306,7 +305,7 @@ namespace SparkleLib { return; // Only trigger the ProgressChanged event once per second - if (DateTime.Compare (this.progress_last_change, DateTime.Now.Subtract (this.progress_change_interval)) >= 0) + if (DateTime.Compare (this.progress_last_change, DateTime.Now.Subtract (new TimeSpan (0, 0, 0, 1))) >= 0) return; if (progress_percentage == 100.0) @@ -350,8 +349,8 @@ namespace SparkleLib { if (Error == ErrorStatus.None && SyncUp ()) { HasUnsyncedChanges = false; - SyncStatusChanged (SyncStatus.Idle); this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision)); + SyncStatusChanged (SyncStatus.Idle); } else { this.poll_interval = PollInterval.Short; @@ -386,7 +385,10 @@ namespace SparkleLib { ChangeSets = GetChangeSets (); - if (!pre_sync_revision.Equals (CurrentRevision) && ChangeSets != null && ChangeSets.Count > 0) { + if (!pre_sync_revision.Equals (CurrentRevision) && + ChangeSets != null && ChangeSets.Count > 0 && + !ChangeSets [0].User.Name.Equals (this.local_config.User.Name)) { + bool emit_change_event = true; foreach (SparkleChange change in ChangeSets [0].Changes) { @@ -406,8 +408,8 @@ namespace SparkleLib { if (HasUnsyncedChanges) { SyncStatusChanged (SyncStatus.SyncUp); - SyncUp (); - HasUnsyncedChanges = false; + if (SyncUp ()) + HasUnsyncedChanges = false; } SyncStatusChanged (SyncStatus.Idle); @@ -422,10 +424,10 @@ namespace SparkleLib { ProgressPercentage = 0.0; ProgressSpeed = 0.0; + SyncStatusChanged (SyncStatus.Idle); + if (!UseCustomWatcher) this.watcher.Enable (); - - SyncStatusChanged (SyncStatus.Idle); } @@ -433,97 +435,58 @@ namespace SparkleLib { { this.listener = SparkleListenerFactory.CreateListener (Name, Identifier); - if (this.listener.IsConnected) { + if (this.listener.IsConnected) this.poll_interval = PollInterval.Long; - new Thread (() => { - if (!this.is_syncing && !HasLocalChanges && HasRemoteChanges) - SyncDownBase (); - - }).Start (); - } - - this.listener.Connected += ListenerConnectedDelegate; this.listener.Disconnected += ListenerDisconnectedDelegate; this.listener.AnnouncementReceived += ListenerAnnouncementReceivedDelegate; - // Start listening if (!this.listener.IsConnected && !this.listener.IsConnecting) this.listener.Connect (); } - // Stop polling when the connection to the irc channel is succesful - private void ListenerConnectedDelegate () - { - this.poll_interval = PollInterval.Long; - this.last_poll = DateTime.Now; - - if (!this.is_syncing) { - // Check for changes manually one more time - if (HasRemoteChanges) - SyncDownBase (); - - // Push changes that were made since the last disconnect - if (HasUnsyncedChanges) - SyncUpBase (); - } - } - - - // Start polling when the connection to the channel is lost private void ListenerDisconnectedDelegate () { this.poll_interval = PollInterval.Short; - SparkleLogger.LogInfo (Name, "Falling back to polling"); + SparkleLogger.LogInfo (Name, "Falling back to regular polling"); } - // Fetch changes when there is an announcement private void ListenerAnnouncementReceivedDelegate (SparkleAnnouncement announcement) { string identifier = Identifier; - if (announcement.FolderIdentifier.Equals (identifier) && - !announcement.Message.Equals (CurrentRevision)) { - + if (!announcement.FolderIdentifier.Equals (identifier)) + return; + + if (!announcement.Message.Equals (CurrentRevision)) { while (this.is_syncing) Thread.Sleep (100); SparkleLogger.LogInfo (Name, "Syncing due to announcement"); SyncDownBase (); - - } else { - if (announcement.FolderIdentifier.Equals (identifier)) - SparkleLogger.LogInfo (Name, "Not syncing, message is for current revision"); } } // Recursively gets a folder's size in bytes - private double CalculateSize (DirectoryInfo parent) + private long CalculateSize (DirectoryInfo parent) { - if (!Directory.Exists (parent.ToString ())) - return 0; - - double size = 0; - if (ExcludePaths.Contains (parent.Name)) return 0; - try { - foreach (FileInfo file in parent.GetFiles ()) { - if (!file.Exists) - return 0; - - size += file.Length; - } + long size = 0; + try { foreach (DirectoryInfo directory in parent.GetDirectories ()) size += CalculateSize (directory); - } catch (Exception) { - return 0; + foreach (FileInfo file in parent.GetFiles ()) + size += file.Length; + + } catch (Exception e) { + SparkleLogger.LogInfo ("Local", "Error calculating directory size", e); } return size; @@ -535,7 +498,6 @@ namespace SparkleLib { this.remote_timer.Stop (); this.remote_timer.Dispose (); - this.listener.Connected -= ListenerConnectedDelegate; this.listener.Disconnected -= ListenerDisconnectedDelegate; this.listener.AnnouncementReceived -= ListenerAnnouncementReceivedDelegate; diff --git a/SparkleLib/SparkleUser.cs b/SparkleLib/SparkleUser.cs index ef44bc4..f15234a 100644 --- a/SparkleLib/SparkleUser.cs +++ b/SparkleLib/SparkleUser.cs @@ -24,7 +24,11 @@ namespace SparkleLib { public readonly string Name; public readonly string Email; + public string PrivateKey; + public string PrivateKeyFilePath; + public string PublicKey; + public string PublicKeyFilePath; public SparkleUser (string name, string email) diff --git a/SparkleLib/SparkleWrappers.cs b/SparkleLib/SparkleWrappers.cs index ca10851..15cc250 100644 --- a/SparkleLib/SparkleWrappers.cs +++ b/SparkleLib/SparkleWrappers.cs @@ -50,21 +50,11 @@ namespace SparkleLib { case SparkleChangeType.Deleted: message = "deleted ‘{0}’"; break; case SparkleChangeType.Moved: message = "moved ‘{0}’"; break; } - - if (Changes.Count == 1) { - return message = string.Format (message, Changes [0].Path); - - } else if (Changes.Count > 1) { - message = string.Format (message, Changes [0].Path); - - if ((Changes.Count - 1) == 1) - return string.Format (message + " and one other event", Changes.Count - 1); - else - return string.Format (message + " and {0} other events", Changes.Count - 1); - - } else { + + if (Changes.Count > 0) + return string.Format (message, Changes [0].Path); + else return "did something magical"; - } } } |