diff --git a/README.md b/README.md index 1f35cbd5..f00504b1 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,12 @@ $ sudo apt-get install gtk-sharp2 mono-runtime mono-devel monodevelop \ libwebkit-cil-dev intltool libtool python-nautilus libndesk-dbus-glib1.0-cil-dev ``` +For Ubuntu `libappindicator` support, install the following package: + +```bash +$ sudo apt-get install libappindicator0.1-cil-dev +``` + #### Fedora (yum): ```bash @@ -80,11 +86,6 @@ $ sudo yum install gtk-sharp2-devel mono-core mono-devel monodevelop \ gnome-doc-utils ``` -For Ubuntu `libappindicator` support, install the following package: - -```bash -$ sudo apt-get install libappindicator0.1-cil-dev -``` You can then build and install SparkleShare like this: diff --git a/SparkleLib/Git/SparkleFetcherGit.cs b/SparkleLib/Git/SparkleFetcherGit.cs index 9c42a9ce..d8e3b0e9 100755 --- a/SparkleLib/Git/SparkleFetcherGit.cs +++ b/SparkleLib/Git/SparkleFetcherGit.cs @@ -187,9 +187,17 @@ namespace SparkleLib { string n = Environment.NewLine; - // Show special characters in the logs config = config.Replace ("[core]" + n, - "[core]" + n + "quotepath = false" + n); + "[core]" + n + "\tquotepath = false" + n + // Show special characters in the logs + "\tpackedGitLimit = 128m" + n + + "\tpackedGitWindowSize = 128m" + n); + + config = config.Replace ("[remote \"origin\"]" + n, + "[pack]" + n + + "\tdeltaCacheSize = 128m" + n + + "\tpackSizeLimit = 128m" + n + + "\twindowMemory = 128m" + n + + "[remote \"origin\"]" + n); // Be case sensitive explicitly to work on Mac config = config.Replace ("ignorecase = true", "ignorecase = false"); @@ -273,6 +281,16 @@ namespace SparkleLib { writer.WriteLine ("/.svn/*"); writer.WriteLine ("*/.svn/*"); + // Mercurial + writer.WriteLine ("/.hg/*"); + writer.WriteLine ("*/.hg/*"); + writer.WriteLine ("*/.hgignore"); + + // Bazaar + writer.WriteLine ("/.bzr/*"); + writer.WriteLine ("*/.bzr/*"); + writer.WriteLine ("*/.bzrignore"); + writer.Close (); @@ -371,25 +389,4 @@ namespace SparkleLib { writer.Close (); } } - - - public class SparkleGit : Process { - - public SparkleGit (string path, string args) : base () - { - EnableRaisingEvents = true; - StartInfo.FileName = SparkleBackend.DefaultBackend.Path; - StartInfo.Arguments = args; - StartInfo.RedirectStandardOutput = true; - StartInfo.UseShellExecute = false; - StartInfo.WorkingDirectory = path; - } - - - new public void Start () - { - SparkleHelpers.DebugInfo ("Cmd", StartInfo.FileName + " " + StartInfo.Arguments); - base.Start (); - } - } } diff --git a/SparkleLib/Git/SparkleGit.cs b/SparkleLib/Git/SparkleGit.cs new file mode 100644 index 00000000..308d73f2 --- /dev/null +++ b/SparkleLib/Git/SparkleGit.cs @@ -0,0 +1,42 @@ +// SparkleShare, a collaboration and sharing tool. +// Copyright (C) 2010 Hylke Bons +// +// 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 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// 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 . + + +using System; +using System.Diagnostics; + +namespace SparkleLib { + + public class SparkleGit : Process { + + public SparkleGit (string path, string args) : base () + { + EnableRaisingEvents = true; + StartInfo.FileName = SparkleBackend.DefaultBackend.Path; + StartInfo.Arguments = args; + StartInfo.RedirectStandardOutput = true; + StartInfo.UseShellExecute = false; + StartInfo.WorkingDirectory = path; + } + + + new public void Start () + { + SparkleHelpers.DebugInfo ("Cmd", StartInfo.FileName + " " + StartInfo.Arguments); + base.Start (); + } + } +} diff --git a/SparkleLib/Git/SparkleRepoGit.cs b/SparkleLib/Git/SparkleRepoGit.cs index 6c1127b3..522ed081 100644 --- a/SparkleLib/Git/SparkleRepoGit.cs +++ b/SparkleLib/Git/SparkleRepoGit.cs @@ -71,22 +71,48 @@ namespace SparkleLib { public override double Size { get { - return CalculateSize ( - new DirectoryInfo (LocalPath) - ); + string file_path = Path.Combine (LocalPath, ".git", "repo_size"); + + try { + return double.Parse (File.ReadAllText (file_path)); + + } catch { + return 0; + } } } public override double HistorySize { get { - return CalculateSize ( - new DirectoryInfo (Path.Combine (LocalPath, ".git")) - ); + string file_path = Path.Combine (LocalPath, ".git", "repo_history_size"); + + try { + return double.Parse (File.ReadAllText (file_path)); + + } catch { + return 0; + } } } + private void CalculateSizes () + { + double size = CalculateSize ( + new DirectoryInfo (LocalPath)); + + double history_size = CalculateSize ( + new DirectoryInfo (Path.Combine (LocalPath, ".git"))); + + string size_file_path = Path.Combine (LocalPath, ".git", "repo_size"); + string history_size_file_path = Path.Combine (LocalPath, ".git", "repo_history_size"); + + File.WriteAllText (size_file_path, size.ToString ()); + File.WriteAllText (history_size_file_path, history_size.ToString ()); + } + + public override string [] UnsyncedFilePaths { get { List file_paths = new List (); @@ -183,9 +209,6 @@ namespace SparkleLib { double percentage = 1.0; Regex progress_regex = new Regex (@"([0-9]+)%", RegexOptions.Compiled); - DateTime last_change = DateTime.Now; - TimeSpan change_interval = new TimeSpan (0, 0, 0, 1); - while (!git.StandardError.EndOfStream) { string line = git.StandardError.ReadLine (); Match match = progress_regex.Match (line); @@ -218,19 +241,13 @@ namespace SparkleLib { if (number >= percentage) { percentage = number; - - if (percentage == 100.0) - percentage = 99.0; - - if (DateTime.Compare (last_change, DateTime.Now.Subtract (change_interval)) < 0) { - base.OnSyncProgressChanged (percentage, speed); - last_change = DateTime.Now; - } + base.OnSyncProgressChanged (percentage, speed); } } git.WaitForExit (); + CalculateSizes (); if (git.ExitCode == 0) return true; @@ -249,9 +266,6 @@ namespace SparkleLib { double percentage = 1.0; Regex progress_regex = new Regex (@"([0-9]+)%", RegexOptions.Compiled); - DateTime last_change = DateTime.Now; - TimeSpan change_interval = new TimeSpan (0, 0, 0, 1); - while (!git.StandardError.EndOfStream) { string line = git.StandardError.ReadLine (); Match match = progress_regex.Match (line); @@ -284,19 +298,13 @@ namespace SparkleLib { if (number >= percentage) { percentage = number; - - if (percentage == 100.0) - percentage = 99.0; - - if (DateTime.Compare (last_change, DateTime.Now.Subtract (change_interval)) < 0) { - base.OnSyncProgressChanged (percentage, speed); - last_change = DateTime.Now; - } + base.OnSyncProgressChanged (percentage, speed); } } git.WaitForExit (); + CalculateSizes (); if (git.ExitCode == 0) { Rebase (); @@ -310,7 +318,7 @@ namespace SparkleLib { public override bool AnyDifferences { get { - FillEmptyDirectories (LocalPath); + PrepareDirectories (LocalPath); SparkleGit git = new SparkleGit (LocalPath, "status --porcelain"); git.Start (); @@ -562,16 +570,24 @@ namespace SparkleLib { string [] lines = output.Split ("\n".ToCharArray ()); List entries = new List (); - int j = 0; + int line_number = 0; + bool first_pass = true; string entry = "", last_entry = ""; foreach (string line in lines) { - if (line.StartsWith ("commit") && j > 0) { + if (line.StartsWith ("commit") && !first_pass) { entries.Add (entry); entry = ""; + line_number = 0; + + } else { + first_pass = false; } - entry += line + "\n"; - j++; + // Only parse 250 files to prevent memory issues + if (line_number < 254) { + entry += line + "\n"; + line_number++; + } last_entry = entry; } @@ -657,6 +673,7 @@ namespace SparkleLib { } } + if ((change_set.Added.Count + change_set.Edited.Count + change_set.Deleted.Count + @@ -673,14 +690,30 @@ namespace SparkleLib { // Git doesn't track empty directories, so this method - // fills them all with a hidden empty file - private void FillEmptyDirectories (string path) + // fills them all with a hidden empty file. + // + // It also prevents git repositories from becoming + // git submodules by renaming the .git/HEAD file + private void PrepareDirectories (string path) { foreach (string child_path in Directory.GetDirectories (path)) { - if (child_path.EndsWith (".git") || child_path.EndsWith (".notes")) + if (child_path.EndsWith (".git") && + !child_path.Equals (Path.Combine (LocalPath, ".git"))) { + + string HEAD_file_path = Path.Combine (child_path, "HEAD"); + + if (File.Exists (HEAD_file_path)) { + File.Move (HEAD_file_path, HEAD_file_path + ".backup"); + SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Renamed " + HEAD_file_path); + } + continue; - FillEmptyDirectories (child_path); + } else if (child_path.EndsWith (".notes")) { + continue; + } + + PrepareDirectories (child_path); } if (Directory.GetFiles (path).Length == 0 && diff --git a/SparkleLib/Makefile.am b/SparkleLib/Makefile.am index b696aa1b..3dd3ac2f 100755 --- a/SparkleLib/Makefile.am +++ b/SparkleLib/Makefile.am @@ -4,6 +4,7 @@ TARGET = library SOURCES = \ Defines.cs \ Git/SparkleFetcherGit.cs \ + Git/SparkleGit.cs \ Git/SparkleRepoGit.cs \ SparkleBackend.cs \ SparkleChangeSet.cs \ diff --git a/SparkleLib/SparkleConfig.cs b/SparkleLib/SparkleConfig.cs index 1c927fe3..4ab51170 100755 --- a/SparkleLib/SparkleConfig.cs +++ b/SparkleLib/SparkleConfig.cs @@ -25,17 +25,17 @@ namespace SparkleLib { public class SparkleConfig : XmlDocument { - public static string ConfigPath = Path.Combine ( + private static string default_config_path = Path.Combine ( Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "sparkleshare"); - public bool DebugMode = true; + public static SparkleConfig DefaultConfig = new SparkleConfig (default_config_path, "config.xml"); + public static bool DebugMode = true; + - public static SparkleConfig DefaultConfig = new SparkleConfig (ConfigPath, "config.xml"); public string FullPath; - public string LogFilePath; public string TmpPath; - + public string LogFilePath; public string HomePath { get { @@ -69,16 +69,12 @@ namespace SparkleLib { } } - if (!Directory.Exists (config_path)) { + 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)) { + string icons_path = Path.Combine (config_path, "icons"); + if (!Directory.Exists (icons_path)) Directory.CreateDirectory (icons_path); - SparkleHelpers.DebugInfo ("Config", "Created \"" + icons_path + "\""); - } try { Load (FullPath); @@ -137,8 +133,6 @@ namespace SparkleLib { " Unknown" + n + " " + n + ""); - - SparkleHelpers.DebugInfo ("Config", "Created \"" + FullPath + "\""); } diff --git a/SparkleLib/SparkleHelpers.cs b/SparkleLib/SparkleHelpers.cs index 8a94ec85..e86424ab 100755 --- a/SparkleLib/SparkleHelpers.cs +++ b/SparkleLib/SparkleHelpers.cs @@ -22,29 +22,25 @@ namespace SparkleLib { public static class SparkleHelpers { - public static bool ShowDebugInfo = true; private static object debug_lock = new object (); // Show debug info if needed public static void DebugInfo (string type, string message) { - if (ShowDebugInfo) { - string timestamp = DateTime.Now.ToString ("HH:mm:ss"); + if (!message.StartsWith ("[")) + message = " " + message; - if (!message.StartsWith ("[")) - message = " " + message; + string timestamp = DateTime.Now.ToString ("HH:mm:ss"); + string line = timestamp + " " + "[" + type + "]" + message; - string line = timestamp + " " + "[" + type + "]" + message; + if (SparkleConfig.DebugMode) + Console.WriteLine (line); - if (SparkleConfig.DefaultConfig.DebugMode) - Console.WriteLine (line); - - lock (debug_lock) { - File.AppendAllText ( - SparkleConfig.DefaultConfig.LogFilePath, - line + Environment.NewLine - ); - } + lock (debug_lock) { + File.AppendAllText ( + SparkleConfig.DefaultConfig.LogFilePath, + line + Environment.NewLine + ); } } diff --git a/SparkleLib/SparkleRepoBase.cs b/SparkleLib/SparkleRepoBase.cs index 0ecb7075..74f367af 100755 --- a/SparkleLib/SparkleRepoBase.cs +++ b/SparkleLib/SparkleRepoBase.cs @@ -130,6 +130,12 @@ namespace SparkleLib { SyncUpBase (); }; + + } + + + public void Initialize () + { // Sync up everything that changed // since we've been offline if (AnyDifferences) { @@ -634,15 +640,25 @@ namespace SparkleLib { } + private DateTime progress_last_change = DateTime.Now; + private TimeSpan progress_change_interval = new TimeSpan (0, 0, 0, 1); + protected void OnSyncProgressChanged (double progress_percentage, string progress_speed) { - // Console.WriteLine ("OnProgressChanged: " + progress_percentage + " " + progress_speed); + if (DateTime.Compare (this.progress_last_change, + DateTime.Now.Subtract (this.progress_change_interval)) < 0) { - this.progress_percentage = progress_percentage; - this.progress_speed = progress_speed; + if (SyncProgressChanged != null) { + if (progress_percentage == 100.0) + progress_percentage = 99.0; - if (SyncProgressChanged != null) - SyncProgressChanged (progress_percentage, progress_speed); + this.progress_percentage = progress_percentage; + this.progress_speed = progress_speed; + this.progress_last_change = DateTime.Now; + + SyncProgressChanged (progress_percentage, progress_speed); + } + } } diff --git a/SparkleShare/Mac/SparkleEventLog.cs b/SparkleShare/Mac/SparkleEventLog.cs index 38af8234..ca9412e6 100755 --- a/SparkleShare/Mac/SparkleEventLog.cs +++ b/SparkleShare/Mac/SparkleEventLog.cs @@ -84,7 +84,7 @@ namespace SparkleShare { Bordered = false, Editable = false, Frame = new RectangleF (60, 588, 75, 20), - StringValue = Controller.Size, + StringValue = "…", Font = SparkleUI.Font }; @@ -105,7 +105,7 @@ namespace SparkleShare { Bordered = false, Editable = false, Frame = new RectangleF (190, 588, 75, 20), - StringValue = Controller.HistorySize, + StringValue = "…", Font = SparkleUI.Font }; diff --git a/SparkleShare/Mac/SparkleStatusIcon.cs b/SparkleShare/Mac/SparkleStatusIcon.cs index d2d4a9cd..f0e75ef0 100755 --- a/SparkleShare/Mac/SparkleStatusIcon.cs +++ b/SparkleShare/Mac/SparkleStatusIcon.cs @@ -84,7 +84,7 @@ namespace SparkleShare { if (Controller.Folders.Length == 0) StateText = _("Welcome to SparkleShare!"); else - StateText = _("Up to date") + " — " + Controller.FolderSize; + StateText = _("Up to date") + Controller.FolderSize; CreateMenu (); @@ -102,7 +102,7 @@ namespace SparkleShare { if (Controller.Folders.Length == 0) StateText = _("Welcome to SparkleShare!"); else - StateText = _("Up to date") + " — " + Controller.FolderSize; + StateText = _("Up to date") + Controller.FolderSize; StateMenuItem.Title = StateText; CreateMenu (); diff --git a/SparkleShare/SparkleController.cs b/SparkleShare/SparkleController.cs index e4736425..3016430d 100755 --- a/SparkleShare/SparkleController.cs +++ b/SparkleShare/SparkleController.cs @@ -181,7 +181,7 @@ namespace SparkleShare { string html = File.ReadAllText (html_path); string jquery_file_path = new string [] {Defines.PREFIX, "share", - "sparkleshare", "html", "jquery.js"}.Combine () + "sparkleshare", "html", "jquery.js"}.Combine (); string jquery = File.ReadAllText (jquery_file_path); html = html.Replace ("", jquery); diff --git a/SparkleShare/SparkleControllerBase.cs b/SparkleShare/SparkleControllerBase.cs index e1bcfc1a..d643d717 100644 --- a/SparkleShare/SparkleControllerBase.cs +++ b/SparkleShare/SparkleControllerBase.cs @@ -224,7 +224,7 @@ namespace SparkleShare { List list = new List (); foreach (SparkleRepoBase repo in Repositories) { - List change_sets = repo.GetChangeSets (50); + List change_sets = repo.GetChangeSets (30); if (change_sets != null) list.AddRange (change_sets); @@ -625,6 +625,7 @@ namespace SparkleShare { }; Repositories.Add (repo); + repo.Initialize (); } @@ -750,14 +751,25 @@ namespace SparkleShare { // so all activity is done with this key public void AddKey () { - string keys_path = Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath); + string keys_path = Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath); string key_file_name = "sparkleshare." + UserEmail + ".key"; + string key_file_path = Path.Combine (keys_path, key_file_name); + + if (!File.Exists (key_file_path)) { + foreach (string file_name in Directory.GetFiles (keys_path)) { + if (file_name.StartsWith ("sparkleshare") && + file_name.EndsWith (".key")) { + + key_file_path = Path.Combine (keys_path, file_name); + } + } + } Process process = new Process (); process.StartInfo.RedirectStandardOutput = true; process.StartInfo.UseShellExecute = false; process.StartInfo.FileName = "ssh-add"; - process.StartInfo.Arguments = "\"" + Path.Combine (keys_path, key_file_name) + "\""; + process.StartInfo.Arguments = "\"" + key_file_path + "\""; process.Start (); process.WaitForExit (); @@ -963,8 +975,10 @@ namespace SparkleShare { remote_folder = remote_folder.Trim (); string tmp_path = SparkleConfig.DefaultConfig.TmpPath; - if (!Directory.Exists (tmp_path)) + if (!Directory.Exists (tmp_path)) { Directory.CreateDirectory (tmp_path); + File.SetAttributes (tmp_path, File.GetAttributes (tmp_path) | FileAttributes.Hidden); + } // Strip the '.git' from the name string canonical_name = Path.GetFileNameWithoutExtension (remote_folder); diff --git a/SparkleShare/SparkleEventLog.cs b/SparkleShare/SparkleEventLog.cs index 72eb817e..5886a5ede 100755 --- a/SparkleShare/SparkleEventLog.cs +++ b/SparkleShare/SparkleEventLog.cs @@ -60,8 +60,7 @@ namespace SparkleShare { DeleteEvent += Close; this.size_label = new Label () { - Markup = "Size: " + Controller.Size + " " + - "History: " + Controller.HistorySize + Markup = "Size:History: …" }; VBox layout_vertical = new VBox (false, 0); diff --git a/SparkleShare/SparkleEventLogController.cs b/SparkleShare/SparkleEventLogController.cs index 9e9cb229..99917216 100755 --- a/SparkleShare/SparkleEventLogController.cs +++ b/SparkleShare/SparkleEventLogController.cs @@ -54,6 +54,9 @@ namespace SparkleShare { if (ContentLoadingEvent != null) ContentLoadingEvent (); + if (UpdateSizeInfoEvent != null) + UpdateSizeInfoEvent ("…", "…"); + Stopwatch watch = new Stopwatch (); watch.Start (); @@ -80,6 +83,10 @@ namespace SparkleShare { public string HTML { get { List change_sets = Program.Controller.GetLog (this.selected_folder); + + if (UpdateSizeInfoEvent != null) + UpdateSizeInfoEvent (Size, HistorySize); + return Program.Controller.GetHTMLLog (change_sets); } } @@ -97,11 +104,18 @@ namespace SparkleShare { foreach (SparkleRepoBase repo in Program.Controller.Repositories) { if (this.selected_folder == null) size += repo.Size; - else if (this.selected_folder.Equals (repo.Name)) - return Program.Controller.FormatSize (repo.Size); + else if (this.selected_folder.Equals (repo.Name)) { + if (repo.Size == 0) + return "???"; + else + return Program.Controller.FormatSize (repo.Size); + } } - return Program.Controller.FormatSize (size); + if (size == 0) + return "???"; + else + return Program.Controller.FormatSize (size); } } @@ -112,11 +126,18 @@ namespace SparkleShare { foreach (SparkleRepoBase repo in Program.Controller.Repositories) { if (this.selected_folder == null) size += repo.HistorySize; - else if (this.selected_folder.Equals (repo.Name)) - return Program.Controller.FormatSize (repo.HistorySize); + else if (this.selected_folder.Equals (repo.Name)) { + if (repo.HistorySize == 0) + return "???"; + else + return Program.Controller.FormatSize (repo.HistorySize); + } } - return Program.Controller.FormatSize (size); + if (size == 0) + return "???"; + else + return Program.Controller.FormatSize (size); } } diff --git a/SparkleShare/SparkleStatusIcon.cs b/SparkleShare/SparkleStatusIcon.cs index 5778f4a4..4d70a5b2 100644 --- a/SparkleShare/SparkleStatusIcon.cs +++ b/SparkleShare/SparkleStatusIcon.cs @@ -74,7 +74,7 @@ namespace SparkleShare { if (Controller.Folders.Length == 0) StateText = _("Welcome to SparkleShare!"); else - StateText = _("Up to date") + " — " + Controller.FolderSize; + StateText = _("Up to date") + Controller.FolderSize; CreateMenu (); @@ -88,7 +88,7 @@ namespace SparkleShare { if (Controller.Folders.Length == 0) StateText = _("Welcome to SparkleShare!"); else - StateText = _("Up to date") + " — " + Controller.FolderSize; + StateText = _("Up to date") + Controller.FolderSize; #if HAVE_APP_INDICATOR this.indicator.IconName = "process-syncing-sparkleshare-i"; @@ -161,7 +161,7 @@ namespace SparkleShare { else FrameNumber = 0; - string icon_name = "process-syncing-sparkleshare"; + string icon_name = "process-syncing-sparkleshare-"; for (int i = 0; i <= FrameNumber; i++) icon_name += "i"; diff --git a/SparkleShare/SparkleStatusIconController.cs b/SparkleShare/SparkleStatusIconController.cs index e8394139..e2a43999 100755 --- a/SparkleShare/SparkleStatusIconController.cs +++ b/SparkleShare/SparkleStatusIconController.cs @@ -50,14 +50,20 @@ namespace SparkleShare { get { double size = 0; - foreach (SparkleRepoBase repo in Program.Controller.Repositories) - size += repo.Size + repo.HistorySize; + foreach (SparkleRepoBase repo in + Program.Controller.Repositories.GetRange ( + 0, Program.Controller.Repositories.Count)) { - return Program.Controller.FormatSize (size); + size += repo.Size + repo.HistorySize; + } + + if (size == 0) + return ""; + else + return " — " + Program.Controller.FormatSize (size); } } - public int ProgressPercentage { get { return (int) Program.Controller.ProgressPercentage; diff --git a/SparkleShare/SparkleUIHelpers.cs b/SparkleShare/SparkleUIHelpers.cs index 7bcc2eb8..68734580 100755 --- a/SparkleShare/SparkleUIHelpers.cs +++ b/SparkleShare/SparkleUIHelpers.cs @@ -46,7 +46,7 @@ namespace SparkleShare { ); icon_theme.AppendSearchPath ( - Path.Combine (SparkleConfig.ConfigPath, "icons") + Path.Combine (Path.GetDirectoryName (SparkleConfig.DefaultConfig.FullPath), "icons") ); try {