Merge branch 'master' into gettext-cs
Conflicts: SparkleLib/Git/SparkleFetcherGit.cs
This commit is contained in:
commit
e2e706dc6a
|
@ -1,4 +1,4 @@
|
|||
basedirs = build help SparkleLib data po
|
||||
basedirs = build SparkleLib data po
|
||||
|
||||
SUBDIRS = $(basedirs) $(GUISUBDIRS)
|
||||
DIST_SUBDIRS = $(basedirs) SparkleShare
|
||||
|
|
11
NEWS
11
NEWS
|
@ -1,4 +1,11 @@
|
|||
0.8.1 for Linux and Mac (Sun Jan 29):
|
||||
0.8.2 for Linux and Mac (Sat Feb 11 2012):
|
||||
|
||||
Hylke:
|
||||
- Use the more reliable and less resource intensive FSEvents on Mac.
|
||||
- Improvements to the reconnect mechanism of the notification system
|
||||
|
||||
|
||||
0.8.1 for Linux and Mac (Sun Jan 29 2012):
|
||||
|
||||
Hylke:
|
||||
- Disable the Quit menu item when a sync is going on
|
||||
|
@ -9,7 +16,7 @@
|
|||
- Close event log on Cmd+W on Mac
|
||||
|
||||
|
||||
0.8.0 for Linux and Mac (Sun Jan 22):
|
||||
0.8.0 for Linux and Mac (Sun Jan 22 2012):
|
||||
|
||||
Hylke:
|
||||
- Show syncing progress in the status icon
|
||||
|
|
|
@ -82,8 +82,7 @@ $ sudo apt-get install libappindicator0.1-cil-dev
|
|||
```bash
|
||||
$ sudo yum install gtk-sharp2-devel mono-core mono-devel monodevelop \
|
||||
ndesk-dbus-devel ndesk-dbus-glib-devel nautilus-python-devel nant \
|
||||
notify-sharp-devel webkit-sharp-devel webkitgtk-devel libtool intltool \
|
||||
gnome-doc-utils
|
||||
notify-sharp-devel webkit-sharp-devel webkitgtk-devel libtool intltool
|
||||
```
|
||||
|
||||
|
||||
|
|
|
@ -79,8 +79,8 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
base.target_folder = target_folder;
|
||||
base.remote_url = uri.ToString ();
|
||||
TargetFolder = target_folder;
|
||||
RemoteUrl = uri.ToString ();
|
||||
}
|
||||
|
||||
|
||||
|
@ -89,8 +89,7 @@ namespace SparkleLib {
|
|||
this.git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath,
|
||||
"clone " +
|
||||
"--progress " + // Redirects progress stats to standarderror
|
||||
"\"" + base.remote_url + "\" " +
|
||||
"\"" + SparkleHelpers.NormalizeSeparatorsToOS(base.target_folder) + "\"");
|
||||
"\"" + RemoteUrl + "\" " + "\"" + SparkleHelpers.NormalizeSeparatorsToOS(TargetFolder) + "\"");
|
||||
|
||||
this.git.StartInfo.RedirectStandardError = true;
|
||||
this.git.Start ();
|
||||
|
@ -140,35 +139,36 @@ namespace SparkleLib {
|
|||
} else {
|
||||
InstallConfiguration ();
|
||||
InstallExcludeRules ();
|
||||
AddWarnings ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override string [] Warnings {
|
||||
get {
|
||||
SparkleGit git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath,
|
||||
"config --global core.excludesfile");
|
||||
private void AddWarnings ()
|
||||
{
|
||||
SparkleGit git = new SparkleGit (SparkleConfig.DefaultConfig.TmpPath,
|
||||
"config --global core.excludesfile");
|
||||
|
||||
git.Start ();
|
||||
git.Start ();
|
||||
|
||||
// Reading the standard output HAS to go before
|
||||
// WaitForExit, or it will hang forever on output > 4096 bytes
|
||||
string output = git.StandardOutput.ReadToEnd ().Trim ();
|
||||
git.WaitForExit ();
|
||||
// Reading the standard output HAS to go before
|
||||
// WaitForExit, or it will hang forever on output > 4096 bytes
|
||||
string output = git.StandardOutput.ReadToEnd ().Trim ();
|
||||
git.WaitForExit ();
|
||||
|
||||
if (string.IsNullOrEmpty (output)) {
|
||||
return null;
|
||||
if (string.IsNullOrEmpty (output)) {
|
||||
return;
|
||||
|
||||
} else {
|
||||
return new string [] {
|
||||
string.Format ("You seem to have configured a system ‘gitignore’ file. " +
|
||||
"This may interfere with SparkleShare.\n({0})", output)
|
||||
};
|
||||
}
|
||||
} else {
|
||||
Warnings = new string [] {
|
||||
string.Format ("You seem to have configured a system ‘gitignore’ file. " +
|
||||
"This may interfere with SparkleShare.\n({0})", output)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Stop ()
|
||||
{
|
||||
if (this.git != null && !this.git.HasExited) {
|
||||
|
@ -176,7 +176,7 @@ namespace SparkleLib {
|
|||
this.git.Dispose ();
|
||||
}
|
||||
|
||||
base.Stop ();
|
||||
Dispose ();
|
||||
}
|
||||
|
||||
|
||||
|
@ -184,7 +184,7 @@ namespace SparkleLib {
|
|||
// the newly cloned repository
|
||||
private void InstallConfiguration ()
|
||||
{
|
||||
string repo_config_file_path = SparkleHelpers.CombineMore (base.target_folder, ".git", "config");
|
||||
string repo_config_file_path = SparkleHelpers.CombineMore (TargetFolder, ".git", "config");
|
||||
string config = String.Join (Environment.NewLine, File.ReadAllLines (repo_config_file_path));
|
||||
|
||||
string n = Environment.NewLine;
|
||||
|
@ -220,7 +220,7 @@ namespace SparkleLib {
|
|||
private void InstallExcludeRules ()
|
||||
{
|
||||
DirectoryInfo info = Directory.CreateDirectory (
|
||||
SparkleHelpers.CombineMore (this.target_folder, ".git", "info"));
|
||||
SparkleHelpers.CombineMore (TargetFolder, ".git", "info"));
|
||||
|
||||
// File that lists the files we want git to ignore
|
||||
string exclude_rules_file_path = Path.Combine (info.FullName, "exclude");
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SparkleLib {
|
||||
|
@ -23,28 +24,58 @@ namespace SparkleLib {
|
|||
public class SparkleGit : Process {
|
||||
|
||||
public static string ExecPath = null;
|
||||
public static string Path = null;
|
||||
|
||||
|
||||
public SparkleGit (string path, string args) : base ()
|
||||
{
|
||||
Path = LocateGit ();
|
||||
|
||||
EnableRaisingEvents = true;
|
||||
StartInfo.FileName = SparkleBackend.DefaultBackend.Path;
|
||||
StartInfo.FileName = Path;
|
||||
StartInfo.RedirectStandardOutput = true;
|
||||
StartInfo.UseShellExecute = false;
|
||||
StartInfo.WorkingDirectory = path;
|
||||
StartInfo.CreateNoWindow = true;
|
||||
|
||||
if (!string.IsNullOrEmpty (ExecPath))
|
||||
StartInfo.Arguments = "--exec-path=\"" + ExecPath + "\" " + args;
|
||||
else
|
||||
if (string.IsNullOrEmpty (ExecPath))
|
||||
StartInfo.Arguments = args;
|
||||
else
|
||||
StartInfo.Arguments = "--exec-path=\"" + ExecPath + "\" " + args;
|
||||
}
|
||||
|
||||
|
||||
new public void Start ()
|
||||
{
|
||||
SparkleHelpers.DebugInfo ("Cmd", "git " + StartInfo.Arguments);
|
||||
base.Start ();
|
||||
|
||||
try {
|
||||
base.Start ();
|
||||
|
||||
} catch (Exception e) {
|
||||
SparkleHelpers.DebugInfo ("Cmd", "There's a problem running Git: " + e.Message);
|
||||
Environment.Exit (-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string LocateGit ()
|
||||
{
|
||||
if (!string.IsNullOrEmpty (Path))
|
||||
return Path;
|
||||
|
||||
string [] possible_git_paths = new string [] {
|
||||
"/usr/bin/git",
|
||||
"/usr/local/bin/git",
|
||||
"/opt/local/bin/git",
|
||||
"/usr/local/git/bin/git"
|
||||
};
|
||||
|
||||
foreach (string path in possible_git_paths)
|
||||
if (File.Exists (path))
|
||||
return path;
|
||||
|
||||
return "git";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,8 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
|
||||
namespace SparkleLib {
|
||||
|
||||
|
@ -63,7 +61,7 @@ namespace SparkleLib {
|
|||
public override List<string> ExcludePaths {
|
||||
get {
|
||||
List<string> rules = new List<string> ();
|
||||
rules.Add (Path.DirectorySeparatorChar + ".git");
|
||||
rules.Add (".git");
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
@ -98,12 +96,12 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
private void CalculateSizes ()
|
||||
private void UpdateSizes ()
|
||||
{
|
||||
double size = CalculateSize (
|
||||
double size = CalculateSizes (
|
||||
new DirectoryInfo (LocalPath));
|
||||
|
||||
double history_size = CalculateSize (
|
||||
double history_size = CalculateSizes (
|
||||
new DirectoryInfo (Path.Combine (LocalPath, ".git")));
|
||||
|
||||
string size_file_path = new string [] {LocalPath, ".git", "repo_size"}.Combine ();
|
||||
|
@ -167,32 +165,36 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public override bool CheckForRemoteChanges ()
|
||||
public override bool HasRemoteChanges
|
||||
{
|
||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Checking for remote changes...");
|
||||
SparkleGit git = new SparkleGit (LocalPath, "ls-remote " + Url + " master");
|
||||
get {
|
||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Checking for remote changes...");
|
||||
SparkleGit git = new SparkleGit (LocalPath, "ls-remote " + Url + " 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 + ")");
|
||||
|
||||
git.Start ();
|
||||
git.WaitForExit ();
|
||||
return true;
|
||||
|
||||
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;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override bool SyncUp ()
|
||||
{
|
||||
if (AnyDifferences) {
|
||||
if (HasLocalChanges) {
|
||||
Add ();
|
||||
|
||||
string message = FormatCommitMessage ();
|
||||
|
@ -242,13 +244,13 @@ namespace SparkleLib {
|
|||
|
||||
if (number >= percentage) {
|
||||
percentage = number;
|
||||
base.OnSyncProgressChanged (percentage, speed);
|
||||
base.OnProgressChanged (percentage, speed);
|
||||
}
|
||||
}
|
||||
|
||||
git.WaitForExit ();
|
||||
|
||||
CalculateSizes ();
|
||||
UpdateSizes ();
|
||||
|
||||
if (git.ExitCode == 0)
|
||||
return true;
|
||||
|
@ -299,13 +301,13 @@ namespace SparkleLib {
|
|||
|
||||
if (number >= percentage) {
|
||||
percentage = number;
|
||||
base.OnSyncProgressChanged (percentage, speed);
|
||||
base.OnProgressChanged (percentage, speed);
|
||||
}
|
||||
}
|
||||
|
||||
git.WaitForExit ();
|
||||
|
||||
CalculateSizes ();
|
||||
UpdateSizes ();
|
||||
|
||||
if (git.ExitCode == 0) {
|
||||
Rebase ();
|
||||
|
@ -317,7 +319,7 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public override bool AnyDifferences {
|
||||
public override bool HasLocalChanges {
|
||||
get {
|
||||
PrepareDirectories (LocalPath);
|
||||
|
||||
|
@ -412,7 +414,7 @@ namespace SparkleLib {
|
|||
{
|
||||
DisableWatching ();
|
||||
|
||||
if (AnyDifferences) {
|
||||
if (HasLocalChanges) {
|
||||
Add ();
|
||||
|
||||
string commit_message = FormatCommitMessage ();
|
||||
|
@ -427,7 +429,7 @@ namespace SparkleLib {
|
|||
if (git.ExitCode != 0) {
|
||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict detected. Trying to get out...");
|
||||
|
||||
while (AnyDifferences)
|
||||
while (HasLocalChanges)
|
||||
ResolveConflict ();
|
||||
|
||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict resolved.");
|
||||
|
@ -653,7 +655,8 @@ namespace SparkleLib {
|
|||
string to_file_path;
|
||||
|
||||
if (file_path.EndsWith (".empty"))
|
||||
file_path = file_path.Substring (0, file_path.Length - ".empty".Length);
|
||||
file_path = file_path.Substring (0,
|
||||
file_path.Length - ".empty".Length);
|
||||
|
||||
if (change_type.Equals ("A") && !file_path.Contains (".notes")) {
|
||||
change_set.Added.Add (file_path);
|
||||
|
@ -669,6 +672,14 @@ namespace SparkleLib {
|
|||
file_path = entry_line.Substring (42, tab_pos - 42);
|
||||
to_file_path = entry_line.Substring (tab_pos + 1);
|
||||
|
||||
if (file_path.EndsWith (".empty"))
|
||||
file_path = file_path.Substring (0,
|
||||
file_path.Length - ".empty".Length);
|
||||
|
||||
if (to_file_path.EndsWith (".empty"))
|
||||
to_file_path = to_file_path.Substring (0,
|
||||
to_file_path.Length - ".empty".Length);
|
||||
|
||||
change_set.MovedFrom.Add (file_path);
|
||||
change_set.MovedTo.Add (to_file_path);
|
||||
}
|
||||
|
@ -807,34 +818,15 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public override bool UsesNotificationCenter
|
||||
{
|
||||
get {
|
||||
string file_path = SparkleHelpers.CombineMore (LocalPath, ".git", "disable_notification_center");
|
||||
return !File.Exists (file_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void CreateInitialChangeSet ()
|
||||
{
|
||||
base.CreateInitialChangeSet ();
|
||||
SyncUp ();
|
||||
}
|
||||
|
||||
|
||||
// Recursively gets a folder's size in bytes
|
||||
public override double CalculateSize (DirectoryInfo parent)
|
||||
private double CalculateSizes (DirectoryInfo parent)
|
||||
{
|
||||
if (!Directory.Exists (parent.ToString ()))
|
||||
return 0;
|
||||
|
||||
double size = 0;
|
||||
|
||||
// Ignore the temporary 'rebase-apply' and '.tmp' directories. This prevents potential
|
||||
// crashes when files are being queried whilst the files have already been deleted.
|
||||
if (parent.Name.Equals ("rebase-apply") ||
|
||||
parent.Name.Equals (".tmp"))
|
||||
if (parent.Name.Equals ("rebase-apply"))
|
||||
return 0;
|
||||
|
||||
try {
|
||||
|
@ -846,7 +838,7 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
foreach (DirectoryInfo directory in parent.GetDirectories ())
|
||||
size += CalculateSize (directory);
|
||||
size += CalculateSizes (directory);
|
||||
|
||||
} catch (Exception) {
|
||||
return 0;
|
||||
|
|
|
@ -6,6 +6,7 @@ SOURCES = \
|
|||
Git/SparkleFetcherGit.cs \
|
||||
Git/SparkleGit.cs \
|
||||
Git/SparkleRepoGit.cs \
|
||||
SparkleAnnouncement.cs \
|
||||
SparkleBackend.cs \
|
||||
SparkleChangeSet.cs \
|
||||
SparkleConfig.cs \
|
||||
|
@ -13,6 +14,7 @@ SOURCES = \
|
|||
SparkleFetcherBase.cs \
|
||||
SparkleHelpers.cs \
|
||||
SparkleListenerBase.cs \
|
||||
SparkleListenerFactory.cs \
|
||||
SparkleListenerTcp.cs \
|
||||
SparkleRepoBase.cs \
|
||||
SparkleWatcher.cs
|
||||
|
|
34
SparkleLib/SparkleAnnouncement.cs
Normal file
34
SparkleLib/SparkleAnnouncement.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
// SparkleShare, a collaboration and sharing tool.
|
||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
using System;
|
||||
|
||||
namespace SparkleLib {
|
||||
|
||||
public class SparkleAnnouncement {
|
||||
|
||||
public readonly string FolderIdentifier;
|
||||
public readonly string Message;
|
||||
|
||||
|
||||
public SparkleAnnouncement (string folder_identifier, string message)
|
||||
{
|
||||
FolderIdentifier = folder_identifier;
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,40 +21,7 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace SparkleLib {
|
||||
|
||||
public class SparkleBackend {
|
||||
|
||||
public static SparkleBackend DefaultBackend = new SparkleBackendGit ();
|
||||
|
||||
public string Name;
|
||||
public string Path;
|
||||
|
||||
|
||||
public SparkleBackend (string name, string [] paths)
|
||||
{
|
||||
Name = name;
|
||||
Path = "git";
|
||||
|
||||
foreach (string path in paths) {
|
||||
if (File.Exists (path)) {
|
||||
Path = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsPresent {
|
||||
get {
|
||||
return (Path != null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsUsablePath (string path)
|
||||
{
|
||||
return (path.Length > 0);
|
||||
}
|
||||
|
||||
public static class SparkleBackend {
|
||||
|
||||
public static string Version {
|
||||
get {
|
||||
|
@ -65,7 +32,7 @@ namespace SparkleLib {
|
|||
|
||||
// Strange magic needed by Platform ()
|
||||
[DllImport ("libc")]
|
||||
static extern int uname (IntPtr buf);
|
||||
private static extern int uname (IntPtr buf);
|
||||
|
||||
|
||||
// This fixes the PlatformID enumeration for MacOSX in Environment.OSVersion.Platform,
|
||||
|
@ -90,44 +57,4 @@ namespace SparkleLib {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SparkleBackendGit : SparkleBackend {
|
||||
|
||||
private static string name = "Git";
|
||||
private static string [] paths = new string [] {
|
||||
"/opt/local/bin/git",
|
||||
"/usr/bin/git",
|
||||
"/usr/local/bin/git",
|
||||
"/usr/local/git/bin/git"
|
||||
};
|
||||
|
||||
public SparkleBackendGit () : base (name, paths) { }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class SparkleBackendHg : SparkleBackend {
|
||||
|
||||
private static string name = "Hg";
|
||||
private static string [] paths = new string [] {
|
||||
"/opt/local/bin/hg",
|
||||
"/usr/bin/hg"
|
||||
};
|
||||
|
||||
public SparkleBackendHg () : base (name, paths) { }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class SparkleBackendScp : SparkleBackend {
|
||||
|
||||
private static string name = "Scp";
|
||||
private static string [] paths = new string [] {
|
||||
"/usr/bin/scp"
|
||||
};
|
||||
|
||||
public SparkleBackendScp () : base (name, paths) { }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace SparkleLib {
|
|||
Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
|
||||
"sparkleshare");
|
||||
|
||||
// TODO: declare elsewhere
|
||||
public static SparkleConfig DefaultConfig = new SparkleConfig (default_config_path, "config.xml");
|
||||
public static bool DebugMode = true;
|
||||
|
||||
|
|
|
@ -16,9 +16,7 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Security.AccessControl;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -37,18 +35,21 @@ namespace SparkleLib {
|
|||
public event FailedEventHandler Failed;
|
||||
public event ProgressChangedEventHandler ProgressChanged;
|
||||
|
||||
public string [] ExcludeRules;
|
||||
public abstract bool Fetch ();
|
||||
public abstract void Stop ();
|
||||
|
||||
protected string target_folder;
|
||||
protected string remote_url;
|
||||
public string TargetFolder;
|
||||
public string RemoteUrl;
|
||||
public string [] ExcludeRules;
|
||||
public string [] Warnings;
|
||||
|
||||
private Thread thread;
|
||||
|
||||
|
||||
public SparkleFetcherBase (string server, string remote_folder, string target_folder)
|
||||
{
|
||||
this.target_folder = target_folder;
|
||||
this.remote_url = server + "/" + remote_folder;
|
||||
TargetFolder = target_folder;
|
||||
RemoteUrl = server + "/" + remote_folder;
|
||||
|
||||
ExcludeRules = new string [] {
|
||||
// gedit and emacs
|
||||
|
@ -121,22 +122,18 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public abstract bool Fetch ();
|
||||
public abstract string [] Warnings { get; }
|
||||
|
||||
|
||||
// Clones the remote repository
|
||||
public void Start ()
|
||||
{
|
||||
SparkleHelpers.DebugInfo ("Fetcher", "[" + this.target_folder + "] Fetching folder: " + this.remote_url);
|
||||
SparkleHelpers.DebugInfo ("Fetcher", "[" + TargetFolder + "] Fetching folder: " + RemoteUrl);
|
||||
|
||||
if (Started != null)
|
||||
Started ();
|
||||
|
||||
if (Directory.Exists (this.target_folder))
|
||||
Directory.Delete (this.target_folder, true);
|
||||
if (Directory.Exists (TargetFolder))
|
||||
Directory.Delete (TargetFolder, true);
|
||||
|
||||
string host = GetHost (this.remote_url);
|
||||
string host = GetHost (RemoteUrl);
|
||||
|
||||
if (String.IsNullOrEmpty (host)) {
|
||||
if (Failed != null)
|
||||
|
@ -170,20 +167,6 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public virtual void Stop ()
|
||||
{
|
||||
this.thread.Abort ();
|
||||
this.thread.Join ();
|
||||
}
|
||||
|
||||
|
||||
public string RemoteUrl {
|
||||
get {
|
||||
return this.remote_url;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
if (this.thread != null) {
|
||||
|
|
|
@ -40,12 +40,14 @@
|
|||
<Compile Include="Git/SparkleFetcherGit.cs" />
|
||||
<Compile Include="Hg/SparkleFetcherHg.cs" />
|
||||
<Compile Include="Defines.cs" />
|
||||
<Compile Include="SparkleAnnouncement.cs" />
|
||||
<Compile Include="SparkleHelpers.cs" />
|
||||
<Compile Include="SparklePaths.cs" />
|
||||
<Compile Include="SparkleOptions.cs" />
|
||||
<Compile Include="SparkleChangeSet.cs" />
|
||||
<Compile Include="SparkleListenerBase.cs" />
|
||||
<Compile Include="SparkleListenerIrc.cs" />
|
||||
<Compile Include="SparkleListenerFactory.cs" />
|
||||
<Compile Include="SparkleListenerTcp.cs" />
|
||||
<Compile Include="SparkleBackend.cs" />
|
||||
<Compile Include="SparkleConfig.cs" />
|
||||
<Compile Include="SparkleWatcher.cs" />
|
||||
|
|
|
@ -16,76 +16,11 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Timers;
|
||||
using System.Linq;
|
||||
|
||||
namespace SparkleLib {
|
||||
|
||||
public class SparkleAnnouncement {
|
||||
|
||||
public readonly string FolderIdentifier;
|
||||
public readonly string Message;
|
||||
|
||||
|
||||
public SparkleAnnouncement (string folder_identifier, string message)
|
||||
{
|
||||
FolderIdentifier = folder_identifier;
|
||||
Message = message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SparkleListenerFactory {
|
||||
|
||||
private static List<SparkleListenerBase> listeners = new List<SparkleListenerBase> ();
|
||||
|
||||
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.AlsoListenToBase (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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A persistent connection to the server that
|
||||
// listens for change notifications
|
||||
public abstract class SparkleListenerBase {
|
||||
|
@ -105,8 +40,8 @@ namespace SparkleLib {
|
|||
public abstract void Connect ();
|
||||
public abstract bool IsConnected { get; }
|
||||
public abstract bool IsConnecting { get; }
|
||||
protected abstract void Announce (SparkleAnnouncement announcent);
|
||||
protected abstract void AlsoListenTo (string folder_identifier);
|
||||
protected abstract void AnnounceInternal (SparkleAnnouncement announcent);
|
||||
protected abstract void AlsoListenToInternal (string folder_identifier);
|
||||
|
||||
|
||||
protected List<string> channels = new List<string> ();
|
||||
|
@ -143,7 +78,7 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public void AnnounceBase (SparkleAnnouncement announcement)
|
||||
public void Announce (SparkleAnnouncement announcement)
|
||||
{
|
||||
if (!IsRecentAnnouncement (announcement)) {
|
||||
if (IsConnected) {
|
||||
|
@ -151,7 +86,7 @@ namespace SparkleLib {
|
|||
"Announcing message " + announcement.Message + " to " +
|
||||
announcement.FolderIdentifier + " on " + Server);
|
||||
|
||||
Announce (announcement);
|
||||
AnnounceInternal (announcement);
|
||||
AddRecentAnnouncement (announcement);
|
||||
|
||||
} else {
|
||||
|
@ -170,14 +105,14 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public void AlsoListenToBase (string channel)
|
||||
public void AlsoListenTo (string channel)
|
||||
{
|
||||
if (!this.channels.Contains (channel) && IsConnected) {
|
||||
SparkleHelpers.DebugInfo ("Listener",
|
||||
"Subscribing to channel " + channel);
|
||||
|
||||
this.channels.Add (channel);
|
||||
AlsoListenTo (channel);
|
||||
AlsoListenToInternal (channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,7 +137,7 @@ namespace SparkleLib {
|
|||
|
||||
foreach (KeyValuePair<string, SparkleAnnouncement> item in this.queue_up) {
|
||||
SparkleAnnouncement announcement = item.Value;
|
||||
AnnounceBase (announcement);
|
||||
Announce (announcement);
|
||||
}
|
||||
|
||||
this.queue_down.Clear ();
|
||||
|
@ -210,9 +145,9 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public void OnDisconnected ()
|
||||
public void OnDisconnected (string message)
|
||||
{
|
||||
SparkleHelpers.DebugInfo ("Listener", "Signal of " + Server + " lost");
|
||||
SparkleHelpers.DebugInfo ("Listener", "Disconnected from " + Server + ": " + message);
|
||||
|
||||
if (Disconnected != null)
|
||||
Disconnected ();
|
||||
|
@ -294,4 +229,3 @@ namespace SparkleLib {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
89
SparkleLib/SparkleListenerFactory.cs
Normal file
89
SparkleLib/SparkleListenerFactory.cs
Normal file
|
@ -0,0 +1,89 @@
|
|||
// SparkleShare, a collaboration and sharing tool.
|
||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SparkleLib {
|
||||
|
||||
public static class SparkleListenerFactory {
|
||||
|
||||
private static List<SparkleListenerBase> listeners = new List<SparkleListenerBase> ();
|
||||
|
||||
|
||||
public static SparkleListenerBase CreateListener (string folder_name, string folder_identifier)
|
||||
{
|
||||
// Check if the user wants to use a global custom notification service
|
||||
string uri = SparkleConfig.DefaultConfig.GetConfigOption ("announcements_url");
|
||||
|
||||
// Check if the user wants a use a custom notification service for this folder
|
||||
if (string.IsNullOrEmpty (uri))
|
||||
uri = SparkleConfig.DefaultConfig.GetFolderOptionalAttribute (
|
||||
folder_name, "announcements_url");
|
||||
|
||||
// Fall back to the fallback service is neither is the case
|
||||
if (string.IsNullOrEmpty (uri)) {
|
||||
// This is SparkleShare's centralized notification service.
|
||||
// It communicates "It's time to sync!" signals between clients.
|
||||
//
|
||||
// Here's how it works: the client listens to a channel (the
|
||||
// folder identifier, a SHA-1 hash) for when it's time to sync.
|
||||
// Clients also send the current revision hash to the channel
|
||||
// for other clients to pick up when you've synced up any
|
||||
// changes.
|
||||
//
|
||||
// Please see the SparkleShare wiki if you wish to run
|
||||
// your own service instead
|
||||
|
||||
uri = "tcp://notifications.sparkleshare.org:1986";
|
||||
}
|
||||
|
||||
Uri announce_uri = new Uri (uri);
|
||||
|
||||
// We use only one listener per notification service 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 " + announce_uri.Scheme +
|
||||
" listener for " + announce_uri);
|
||||
|
||||
// We already seem to have a listener for this server,
|
||||
// refer to the existing one instead
|
||||
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 " + announce_uri.Scheme + " listener for " + announce_uri);
|
||||
|
||||
return (SparkleListenerBase) listeners [listeners.Count - 1];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,23 +16,20 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace SparkleLib {
|
||||
|
||||
public class SparkleListenerTcp : SparkleListenerBase {
|
||||
|
||||
private Socket socket;
|
||||
private Object socket_lock = new Object ();
|
||||
private Thread thread;
|
||||
private bool is_connected = false;
|
||||
private bool is_connecting = false;
|
||||
private Object socket_lock = new Object ();
|
||||
private bool is_connected = false;
|
||||
private bool is_connecting = false;
|
||||
private DateTime last_ping = DateTime.Now;
|
||||
|
||||
|
||||
public SparkleListenerTcp (Uri server, string folder_identifier) :
|
||||
|
@ -60,83 +57,138 @@ namespace SparkleLib {
|
|||
// Starts a new thread and listens to the channel
|
||||
public override void Connect ()
|
||||
{
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp", "Connecting to " + Server.Host);
|
||||
|
||||
this.is_connecting = true;
|
||||
|
||||
this.thread = new Thread (
|
||||
new ThreadStart (delegate {
|
||||
int port = Server.Port;
|
||||
|
||||
if (port < 0)
|
||||
port = 1986;
|
||||
|
||||
try {
|
||||
// Connect and subscribe to the channel
|
||||
int port = Server.Port;
|
||||
|
||||
if (port < 0)
|
||||
port = 9999;
|
||||
|
||||
|
||||
lock (this.socket_lock) {
|
||||
this.socket = new Socket (AddressFamily.InterNetwork,
|
||||
SocketType.Stream, ProtocolType.Tcp) {
|
||||
|
||||
ReceiveTimeout = 30 * 1000
|
||||
ReceiveTimeout = 5 * 1000,
|
||||
SendTimeout = 5 * 1000
|
||||
};
|
||||
|
||||
// Try to connect to the server
|
||||
this.socket.Connect (Server.Host, port);
|
||||
|
||||
this.is_connecting = false;
|
||||
this.is_connected = true;
|
||||
this.is_connected = true;
|
||||
|
||||
OnConnected ();
|
||||
|
||||
foreach (string channel in base.channels) {
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp", "Subscribing to channel " + channel);
|
||||
this.socket.Send (Encoding.UTF8.GetBytes ("subscribe " + channel + "\n"));
|
||||
}
|
||||
// Subscribe to channels of interest to us
|
||||
foreach (string channel in base.channels)
|
||||
AlsoListenToInternal (channel);
|
||||
}
|
||||
|
||||
|
||||
byte [] bytes = new byte [4096];
|
||||
|
||||
// List to the channels, this blocks the thread
|
||||
while (this.socket.Connected) {
|
||||
int bytes_read = this.socket.Receive (bytes);
|
||||
|
||||
if (bytes_read > 0) {
|
||||
string received = Encoding.UTF8.GetString (bytes);
|
||||
string line = received.Substring (0, received.IndexOf ("\n"));
|
||||
|
||||
if (!line.Contains ("!"))
|
||||
continue;
|
||||
|
||||
string folder_identifier = line.Substring (0, line.IndexOf ("!"));
|
||||
string message = CleanMessage (line.Substring (line.IndexOf ("!") + 1));
|
||||
|
||||
if (!folder_identifier.Equals ("debug") &&
|
||||
!String.IsNullOrEmpty (message)) {
|
||||
|
||||
OnAnnouncement (new SparkleAnnouncement (folder_identifier, message));
|
||||
}
|
||||
|
||||
} else {
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp", "Error on socket");
|
||||
|
||||
lock (this.socket_lock) {
|
||||
this.socket.Close ();
|
||||
this.is_connected = false;
|
||||
|
||||
OnDisconnected ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp", "Disconnected from " + Server.Host);
|
||||
|
||||
} catch (SocketException e) {
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp", "Could not connect to " + Server + ": " + e.Message);
|
||||
this.is_connected = false;
|
||||
this.is_connected = false;
|
||||
this.is_connecting = false;
|
||||
|
||||
OnDisconnected ();
|
||||
this.socket.Dispose ();
|
||||
|
||||
OnDisconnected (e.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
byte [] bytes = new byte [4096];
|
||||
int bytes_read = 0;
|
||||
this.last_ping = DateTime.Now;
|
||||
|
||||
// Wait for messages
|
||||
while (this.is_connected) {
|
||||
|
||||
// This blocks the thread
|
||||
int i = 0;
|
||||
while (this.socket.Available < 1) {
|
||||
Thread.Sleep (1000);
|
||||
i++;
|
||||
|
||||
try {
|
||||
// We've timed out, let's ping the server to
|
||||
// see if the connection is still up
|
||||
if (i == 180) {
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp",
|
||||
"Pinging " + Server);
|
||||
|
||||
byte [] ping_bytes = Encoding.UTF8.GetBytes ("ping\n");
|
||||
byte [] pong_bytes = new byte [4096];
|
||||
|
||||
lock (this.socket_lock)
|
||||
this.socket.Send (ping_bytes);
|
||||
|
||||
if (this.socket.Receive (pong_bytes) < 1)
|
||||
// 10057 means "Socket is not connected"
|
||||
throw new SocketException (10057);
|
||||
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp",
|
||||
"Received pong from " + Server);
|
||||
|
||||
i = 0;
|
||||
this.last_ping = DateTime.Now;
|
||||
|
||||
} else {
|
||||
// Check when the last ping occured. If it's
|
||||
// significantly longer than our regular interval the
|
||||
// system likely woke up from sleep and we want to
|
||||
// simulate a disconnect
|
||||
int sleepiness = DateTime.Compare (
|
||||
this.last_ping.AddMilliseconds (180 * 1000 * 1.2),
|
||||
DateTime.Now
|
||||
);
|
||||
|
||||
if (sleepiness <= 0) {
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp",
|
||||
"System woke up from sleep");
|
||||
|
||||
// 10057 means "Socket is not connected"
|
||||
throw new SocketException (10057);
|
||||
}
|
||||
}
|
||||
|
||||
// The ping failed: disconnect completely
|
||||
} catch (SocketException) {
|
||||
this.is_connected = false;
|
||||
this.is_connecting = false;;
|
||||
|
||||
this.socket.Dispose ();
|
||||
|
||||
OnDisconnected ("Ping timeout");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (this.socket.Available > 0)
|
||||
lock (this.socket_lock)
|
||||
bytes_read = this.socket.Receive (bytes);
|
||||
|
||||
|
||||
// Parse the received message
|
||||
if (bytes_read > 0) {
|
||||
string received = Encoding.UTF8.GetString (bytes);
|
||||
string line = received.Substring (0, received.IndexOf ("\n"));
|
||||
|
||||
if (!line.Contains ("!"))
|
||||
continue;
|
||||
|
||||
string folder_identifier = line.Substring (0, line.IndexOf ("!"));
|
||||
string message = CleanMessage (line.Substring (line.IndexOf ("!") + 1));
|
||||
|
||||
if (!folder_identifier.Equals ("debug") &&
|
||||
!String.IsNullOrEmpty (message)) {
|
||||
|
||||
// We have a message!
|
||||
OnAnnouncement (new SparkleAnnouncement (folder_identifier, message));
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -145,28 +197,29 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
protected override void AlsoListenTo (string folder_identifier)
|
||||
protected override void AlsoListenToInternal (string folder_identifier)
|
||||
{
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp",
|
||||
"Subscribing to channel " + folder_identifier + " on " + Server);
|
||||
|
||||
string to_send = "subscribe " + folder_identifier + "\n";
|
||||
|
||||
try {
|
||||
lock (this.socket_lock) {
|
||||
lock (this.socket_lock)
|
||||
this.socket.Send (Encoding.UTF8.GetBytes (to_send));
|
||||
}
|
||||
|
||||
this.last_ping = DateTime.Now;
|
||||
|
||||
} catch (SocketException e) {
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp",
|
||||
"Could not connect to " + Server + ": " + e.Message);
|
||||
|
||||
this.is_connected = false;
|
||||
this.is_connecting = false;
|
||||
|
||||
OnDisconnected ();
|
||||
OnDisconnected (e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void Announce (SparkleAnnouncement announcement)
|
||||
protected override void AnnounceInternal (SparkleAnnouncement announcement)
|
||||
{
|
||||
string to_send = "announce " + announcement.FolderIdentifier
|
||||
+ " " + announcement.Message + "\n";
|
||||
|
@ -175,14 +228,13 @@ namespace SparkleLib {
|
|||
lock (this.socket_lock)
|
||||
this.socket.Send (Encoding.UTF8.GetBytes (to_send));
|
||||
|
||||
} catch (SocketException e) {
|
||||
SparkleHelpers.DebugInfo ("ListenerTcp",
|
||||
"Could not connect to " + Server + ": " + e.Message);
|
||||
this.last_ping = DateTime.Now;
|
||||
|
||||
} catch (SocketException e) {
|
||||
this.is_connected = false;
|
||||
this.is_connecting = false;
|
||||
|
||||
OnDisconnected ();
|
||||
OnDisconnected (e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,7 +23,6 @@ using System.Text;
|
|||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Timers;
|
||||
using System.Xml;
|
||||
|
||||
namespace SparkleLib {
|
||||
|
||||
|
@ -39,45 +38,28 @@ namespace SparkleLib {
|
|||
|
||||
private TimeSpan short_interval = new TimeSpan (0, 0, 3, 0);
|
||||
private TimeSpan long_interval = new TimeSpan (0, 0, 10, 0);
|
||||
|
||||
private SparkleWatcher watcher;
|
||||
private TimeSpan poll_interval;
|
||||
private SparkleWatcher watcher;
|
||||
private SparkleListenerBase listener;
|
||||
private System.Timers.Timer local_timer = new System.Timers.Timer () { Interval = 0.25 * 1000 };
|
||||
private System.Timers.Timer remote_timer = new System.Timers.Timer () { Interval = 10 * 1000 };
|
||||
private DateTime last_poll = DateTime.Now;
|
||||
private List<double> sizebuffer = new List<double> ();
|
||||
private bool has_changed = false;
|
||||
private Object change_lock = new Object ();
|
||||
private Object watch_lock = new Object ();
|
||||
private double progress_percentage = 0.0;
|
||||
private string progress_speed = "";
|
||||
private DateTime last_poll = DateTime.Now;
|
||||
private List<double> size_buffer = new List<double> ();
|
||||
private Object change_lock = new Object ();
|
||||
private Object watch_lock = new Object ();
|
||||
private double progress_percentage = 0.0;
|
||||
private string progress_speed = "";
|
||||
private bool has_changed = false;
|
||||
private bool is_buffering = false;
|
||||
private bool server_online = true;
|
||||
private SyncStatus status;
|
||||
|
||||
protected SparkleListenerBase listener;
|
||||
protected SyncStatus status;
|
||||
protected bool is_buffering = false;
|
||||
protected bool server_online = true;
|
||||
|
||||
public readonly string LocalPath;
|
||||
public readonly string Name;
|
||||
public readonly Uri Url;
|
||||
|
||||
public abstract bool AnyDifferences { get; }
|
||||
public abstract string Identifier { get; }
|
||||
public abstract string CurrentRevision { get; }
|
||||
public abstract bool SyncUp ();
|
||||
public abstract bool SyncDown ();
|
||||
public abstract double CalculateSize (DirectoryInfo parent);
|
||||
public abstract bool HasUnsyncedChanges { get; set; }
|
||||
public abstract List<string> ExcludePaths { get; }
|
||||
|
||||
public abstract double Size { get; }
|
||||
public abstract double HistorySize { get; }
|
||||
|
||||
public delegate void SyncStatusChangedEventHandler (SyncStatus new_status);
|
||||
public event SyncStatusChangedEventHandler SyncStatusChanged;
|
||||
|
||||
public delegate void SyncProgressChangedEventHandler (double percentage, string speed);
|
||||
public event SyncProgressChangedEventHandler SyncProgressChanged;
|
||||
public delegate void ProgressChangedEventHandler (double percentage, string speed);
|
||||
public event ProgressChangedEventHandler ProgressChanged;
|
||||
|
||||
public delegate void NewChangeSetEventHandler (SparkleChangeSet change_set);
|
||||
public event NewChangeSetEventHandler NewChangeSet;
|
||||
|
@ -92,6 +74,68 @@ namespace SparkleLib {
|
|||
public event ChangesDetectedEventHandler ChangesDetected;
|
||||
|
||||
|
||||
public readonly string LocalPath;
|
||||
public readonly string Name;
|
||||
public readonly Uri Url;
|
||||
|
||||
public abstract string Identifier { 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 (int count);
|
||||
|
||||
|
||||
public bool ServerOnline {
|
||||
get {
|
||||
return this.server_online;
|
||||
}
|
||||
}
|
||||
|
||||
public SyncStatus Status {
|
||||
get {
|
||||
return this.status;
|
||||
}
|
||||
}
|
||||
|
||||
public double ProgressPercentage {
|
||||
get {
|
||||
return this.progress_percentage;
|
||||
}
|
||||
}
|
||||
|
||||
public string ProgressSpeed {
|
||||
get {
|
||||
return this.progress_speed;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string [] UnsyncedFilePaths {
|
||||
get {
|
||||
return new string [0];
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSyncing {
|
||||
get {
|
||||
return (Status == SyncStatus.SyncUp ||
|
||||
Status == SyncStatus.SyncDown ||
|
||||
this.is_buffering);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsBuffering {
|
||||
get {
|
||||
return this.is_buffering;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public SparkleRepoBase (string path)
|
||||
{
|
||||
LocalPath = path;
|
||||
|
@ -121,7 +165,7 @@ namespace SparkleLib {
|
|||
if (time_to_poll) {
|
||||
this.last_poll = DateTime.Now;
|
||||
|
||||
if (CheckForRemoteChanges ())
|
||||
if (HasRemoteChanges)
|
||||
SyncDownBase ();
|
||||
}
|
||||
|
||||
|
@ -139,7 +183,7 @@ namespace SparkleLib {
|
|||
{
|
||||
// Sync up everything that changed
|
||||
// since we've been offline
|
||||
if (AnyDifferences) {
|
||||
if (HasLocalChanges) {
|
||||
DisableWatching ();
|
||||
SyncUpBase ();
|
||||
|
||||
|
@ -154,96 +198,15 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public bool ServerOnline {
|
||||
get {
|
||||
return this.server_online;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public SyncStatus Status {
|
||||
get {
|
||||
return this.status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public double ProgressPercentage {
|
||||
get {
|
||||
return this.progress_percentage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string ProgressSpeed {
|
||||
get {
|
||||
return this.progress_speed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual string [] UnsyncedFilePaths {
|
||||
get {
|
||||
return new string [0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string Domain {
|
||||
get {
|
||||
Regex regex = new Regex (@"(@|://)([a-z0-9\.-]+)(/|:)");
|
||||
Match match = regex.Match (SparkleConfig.DefaultConfig.GetUrlForFolder (Name));
|
||||
|
||||
if (match.Success)
|
||||
return match.Groups [2].Value;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void OnConflictResolved ()
|
||||
{
|
||||
HasUnsyncedChanges = true;
|
||||
HasUnsyncedChanges = true; // ?
|
||||
|
||||
if (ConflictResolved != null)
|
||||
ConflictResolved ();
|
||||
}
|
||||
|
||||
|
||||
public virtual bool CheckForRemoteChanges () // TODO: HasRemoteChanges { get; }
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public virtual List<SparkleChangeSet> GetChangeSets (int count) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public virtual bool UsesNotificationCenter {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string RemoteName {
|
||||
get {
|
||||
string url = SparkleConfig.DefaultConfig.GetUrlForFolder (Name);
|
||||
return Path.GetFileNameWithoutExtension (url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsBuffering {
|
||||
get {
|
||||
return this.is_buffering;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Disposes all resourses of this object
|
||||
public void Dispose ()
|
||||
{
|
||||
|
@ -253,114 +216,6 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
private void CreateWatcher ()
|
||||
{
|
||||
this.watcher = new SparkleWatcher (LocalPath);
|
||||
this.watcher.ChangeEvent += delegate (FileSystemEventArgs args) {
|
||||
OnFileActivity (args);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public void CreateListener ()
|
||||
{
|
||||
this.listener = SparkleListenerFactory.CreateListener (Name, Identifier);
|
||||
|
||||
if (this.listener.IsConnected) {
|
||||
this.poll_interval = this.long_interval;
|
||||
|
||||
new Thread (new ThreadStart (delegate {
|
||||
if (!IsSyncing && CheckForRemoteChanges ())
|
||||
SyncDownBase ();
|
||||
})).Start ();
|
||||
}
|
||||
|
||||
// Stop polling when the connection to the irc channel is succesful
|
||||
this.listener.Connected += delegate {
|
||||
this.poll_interval = this.long_interval;
|
||||
this.last_poll = DateTime.Now;
|
||||
|
||||
if (!IsSyncing) {
|
||||
|
||||
// Check for changes manually one more time
|
||||
if (CheckForRemoteChanges ())
|
||||
SyncDownBase ();
|
||||
|
||||
// Push changes that were made since the last disconnect
|
||||
if (HasUnsyncedChanges)
|
||||
SyncUpBase ();
|
||||
}
|
||||
};
|
||||
|
||||
// Start polling when the connection to the irc channel is lost
|
||||
this.listener.Disconnected += delegate {
|
||||
this.poll_interval = this.short_interval;
|
||||
SparkleHelpers.DebugInfo (Name, "Falling back to polling");
|
||||
};
|
||||
|
||||
// Fetch changes when there is a message in the irc channel
|
||||
this.listener.Received += delegate (SparkleAnnouncement announcement) {
|
||||
string identifier = Identifier;
|
||||
|
||||
if (announcement.FolderIdentifier.Equals (identifier) &&
|
||||
!announcement.Message.Equals (CurrentRevision)) {
|
||||
|
||||
while (this.IsSyncing)
|
||||
System.Threading.Thread.Sleep (100);
|
||||
|
||||
SparkleHelpers.DebugInfo ("Listener", "Syncing due to announcement");
|
||||
SyncDownBase ();
|
||||
|
||||
} else {
|
||||
if (announcement.FolderIdentifier.Equals (identifier))
|
||||
SparkleHelpers.DebugInfo ("Listener", "Not syncing, message is for current revision");
|
||||
}
|
||||
};
|
||||
|
||||
// Start listening
|
||||
if (!this.listener.IsConnected && !this.listener.IsConnecting)
|
||||
this.listener.Connect ();
|
||||
}
|
||||
|
||||
|
||||
public bool IsSyncing {
|
||||
get {
|
||||
return (Status == SyncStatus.SyncUp ||
|
||||
Status == SyncStatus.SyncDown ||
|
||||
this.is_buffering);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Starts a timer when something changes
|
||||
public void OnFileActivity (FileSystemEventArgs args)
|
||||
{
|
||||
|
@ -378,7 +233,7 @@ namespace SparkleLib {
|
|||
|
||||
WatcherChangeTypes wct = args.ChangeType;
|
||||
|
||||
if (AnyDifferences) {
|
||||
if (HasLocalChanges) {
|
||||
this.is_buffering = true;
|
||||
|
||||
// We want to disable wathcing temporarily, but
|
||||
|
@ -440,6 +295,44 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public void AddNote (string revision, string note)
|
||||
{
|
||||
string notes_path = Path.Combine (LocalPath, ".notes");
|
||||
|
||||
if (!Directory.Exists (notes_path))
|
||||
Directory.CreateDirectory (notes_path);
|
||||
|
||||
// Add a timestamp in seconds since unix epoch
|
||||
int timestamp = (int) (DateTime.UtcNow - new DateTime (1970, 1, 1)).TotalSeconds;
|
||||
|
||||
string n = Environment.NewLine;
|
||||
note = "<note>" + n +
|
||||
" <user>" + n +
|
||||
" <name>" + SparkleConfig.DefaultConfig.User.Name + "</name>" + n +
|
||||
" <email>" + SparkleConfig.DefaultConfig.User.Email + "</email>" + n +
|
||||
" </user>" + n +
|
||||
" <timestamp>" + timestamp + "</timestamp>" + n +
|
||||
" <body>" + note + "</body>" + n +
|
||||
"</note>" + n;
|
||||
|
||||
string note_name = revision + SHA1 (timestamp.ToString () + note);
|
||||
string note_path = Path.Combine (notes_path, note_name);
|
||||
|
||||
StreamWriter writer = new StreamWriter (note_path);
|
||||
writer.Write (note);
|
||||
writer.Close ();
|
||||
|
||||
|
||||
// The watcher doesn't like .*/ so we need to trigger
|
||||
// a change manually
|
||||
FileSystemEventArgs args = new FileSystemEventArgs (WatcherChangeTypes.Changed,
|
||||
notes_path, note_name);
|
||||
|
||||
OnFileActivity (args);
|
||||
SparkleHelpers.DebugInfo ("Note", "Added note to " + revision);
|
||||
}
|
||||
|
||||
|
||||
private void SyncUpBase ()
|
||||
{
|
||||
try {
|
||||
|
@ -459,7 +352,7 @@ namespace SparkleLib {
|
|||
if (SyncStatusChanged != null)
|
||||
SyncStatusChanged (SyncStatus.Idle);
|
||||
|
||||
this.listener.AnnounceBase (new SparkleAnnouncement (Identifier, CurrentRevision));
|
||||
this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision));
|
||||
|
||||
} else {
|
||||
SparkleHelpers.DebugInfo ("SyncUp", "[" + Name + "] Error");
|
||||
|
@ -474,7 +367,7 @@ namespace SparkleLib {
|
|||
if (SyncStatusChanged != null)
|
||||
SyncStatusChanged (SyncStatus.Idle);
|
||||
|
||||
this.listener.AnnounceBase (new SparkleAnnouncement (Identifier, CurrentRevision));
|
||||
this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision));
|
||||
|
||||
} else {
|
||||
this.server_online = false;
|
||||
|
@ -561,7 +454,106 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public void DisableWatching ()
|
||||
private void CreateWatcher ()
|
||||
{
|
||||
this.watcher = new SparkleWatcher (LocalPath);
|
||||
this.watcher.ChangeEvent += delegate (FileSystemEventArgs args) {
|
||||
OnFileActivity (args);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private void CreateListener ()
|
||||
{
|
||||
this.listener = SparkleListenerFactory.CreateListener (Name, Identifier);
|
||||
|
||||
if (this.listener.IsConnected) {
|
||||
this.poll_interval = this.long_interval;
|
||||
|
||||
new Thread (new ThreadStart (delegate {
|
||||
if (!IsSyncing && HasRemoteChanges)
|
||||
SyncDownBase ();
|
||||
})).Start ();
|
||||
}
|
||||
|
||||
// Stop polling when the connection to the irc channel is succesful
|
||||
this.listener.Connected += delegate {
|
||||
this.poll_interval = this.long_interval;
|
||||
this.last_poll = DateTime.Now;
|
||||
|
||||
if (!IsSyncing) {
|
||||
|
||||
// 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 irc channel is lost
|
||||
this.listener.Disconnected += delegate {
|
||||
this.poll_interval = this.short_interval;
|
||||
SparkleHelpers.DebugInfo (Name, "Falling back to polling");
|
||||
};
|
||||
|
||||
// Fetch changes when there is a message in the irc channel
|
||||
this.listener.Received += delegate (SparkleAnnouncement announcement) {
|
||||
string identifier = Identifier;
|
||||
|
||||
if (announcement.FolderIdentifier.Equals (identifier) &&
|
||||
!announcement.Message.Equals (CurrentRevision)) {
|
||||
|
||||
while (this.IsSyncing)
|
||||
System.Threading.Thread.Sleep (100);
|
||||
|
||||
SparkleHelpers.DebugInfo ("Listener", "Syncing due to announcement");
|
||||
SyncDownBase ();
|
||||
|
||||
} else {
|
||||
if (announcement.FolderIdentifier.Equals (identifier))
|
||||
SparkleHelpers.DebugInfo ("Listener", "Not syncing, message is for current revision");
|
||||
}
|
||||
};
|
||||
|
||||
// Start listening
|
||||
if (!this.listener.IsConnected && !this.listener.IsConnecting)
|
||||
this.listener.Connect ();
|
||||
}
|
||||
|
||||
|
||||
private void CheckForChanges ()
|
||||
{
|
||||
lock (this.change_lock) {
|
||||
if (this.has_changed) {
|
||||
if (this.size_buffer.Count >= 4)
|
||||
this.size_buffer.RemoveAt (0);
|
||||
|
||||
DirectoryInfo dir_info = new DirectoryInfo (LocalPath);
|
||||
this.size_buffer.Add (CalculateSize (dir_info));
|
||||
|
||||
if (this.size_buffer.Count >= 4 &&
|
||||
this.size_buffer [0].Equals (this.size_buffer [1]) &&
|
||||
this.size_buffer [1].Equals (this.size_buffer [2]) &&
|
||||
this.size_buffer [2].Equals (this.size_buffer [3])) {
|
||||
|
||||
SparkleHelpers.DebugInfo ("Local", "[" + Name + "] Changes have settled.");
|
||||
this.is_buffering = false;
|
||||
this.has_changed = false;
|
||||
|
||||
DisableWatching ();
|
||||
while (HasLocalChanges)
|
||||
SyncUpBase ();
|
||||
EnableWatching ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void DisableWatching ()
|
||||
{
|
||||
lock (this.watch_lock) {
|
||||
this.watcher.EnableRaisingEvents = false;
|
||||
|
@ -570,7 +562,7 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
public void EnableWatching ()
|
||||
protected void EnableWatching ()
|
||||
{
|
||||
lock (this.watch_lock) {
|
||||
this.watcher.EnableRaisingEvents = true;
|
||||
|
@ -579,17 +571,39 @@ namespace SparkleLib {
|
|||
}
|
||||
|
||||
|
||||
private DateTime progress_last_change = DateTime.Now;
|
||||
private TimeSpan progress_change_interval = new TimeSpan (0, 0, 0, 1);
|
||||
|
||||
protected void OnProgressChanged (double progress_percentage, string progress_speed)
|
||||
{
|
||||
if (DateTime.Compare (this.progress_last_change,
|
||||
DateTime.Now.Subtract (this.progress_change_interval)) < 0) {
|
||||
|
||||
if (ProgressChanged != null) {
|
||||
if (progress_percentage == 100.0)
|
||||
progress_percentage = 99.0;
|
||||
|
||||
this.progress_percentage = progress_percentage;
|
||||
this.progress_speed = progress_speed;
|
||||
this.progress_last_change = DateTime.Now;
|
||||
|
||||
ProgressChanged (progress_percentage, progress_speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create an initial change set when the
|
||||
// user has fetched an empty remote folder
|
||||
public virtual void CreateInitialChangeSet ()
|
||||
private void CreateInitialChangeSet ()
|
||||
{
|
||||
string file_path = Path.Combine (LocalPath, "SparkleShare.txt");
|
||||
TextWriter writer = new StreamWriter (file_path);
|
||||
|
||||
writer.WriteLine ("Congratulations, you've successfully created a SparkleShare repository!");
|
||||
writer.WriteLine ("");
|
||||
writer.WriteLine ("Any files you add or change in this folder will be automatically synced to ");
|
||||
writer.WriteLine (SparkleConfig.DefaultConfig.GetUrlForFolder (Name) + " and everyone connected to it.");
|
||||
// TODO: Url property? ^
|
||||
writer.WriteLine (Url + " and everyone connected to it.");
|
||||
|
||||
writer.WriteLine ("");
|
||||
writer.WriteLine ("SparkleShare is a Free and Open Source software program that helps people ");
|
||||
|
@ -600,66 +614,8 @@ namespace SparkleLib {
|
|||
writer.WriteLine ("");
|
||||
|
||||
writer.Close ();
|
||||
}
|
||||
|
||||
|
||||
public void AddNote (string revision, string note)
|
||||
{
|
||||
string notes_path = Path.Combine (LocalPath, ".notes");
|
||||
|
||||
if (!Directory.Exists (notes_path))
|
||||
Directory.CreateDirectory (notes_path);
|
||||
|
||||
// Add a timestamp in seconds since unix epoch
|
||||
int timestamp = (int) (DateTime.UtcNow - new DateTime (1970, 1, 1)).TotalSeconds;
|
||||
|
||||
string n = Environment.NewLine;
|
||||
note = "<note>" + n +
|
||||
" <user>" + n +
|
||||
" <name>" + SparkleConfig.DefaultConfig.User.Name + "</name>" + n +
|
||||
" <email>" + SparkleConfig.DefaultConfig.User.Email + "</email>" + n +
|
||||
" </user>" + n +
|
||||
" <timestamp>" + timestamp + "</timestamp>" + n +
|
||||
" <body>" + note + "</body>" + n +
|
||||
"</note>" + n;
|
||||
|
||||
string note_name = revision + SHA1 (timestamp.ToString () + note);
|
||||
string note_path = Path.Combine (notes_path, note_name);
|
||||
|
||||
StreamWriter writer = new StreamWriter (note_path);
|
||||
writer.Write (note);
|
||||
writer.Close ();
|
||||
|
||||
|
||||
// The watcher doesn't like .*/ so we need to trigger
|
||||
// a change manually
|
||||
FileSystemEventArgs args = new FileSystemEventArgs (WatcherChangeTypes.Changed,
|
||||
notes_path, note_name);
|
||||
|
||||
OnFileActivity (args);
|
||||
SparkleHelpers.DebugInfo ("Note", "Added note to " + revision);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (DateTime.Compare (this.progress_last_change,
|
||||
DateTime.Now.Subtract (this.progress_change_interval)) < 0) {
|
||||
|
||||
if (SyncProgressChanged != null) {
|
||||
if (progress_percentage == 100.0)
|
||||
progress_percentage = 99.0;
|
||||
|
||||
this.progress_percentage = progress_percentage;
|
||||
this.progress_speed = progress_speed;
|
||||
this.progress_last_change = DateTime.Now;
|
||||
|
||||
SyncProgressChanged (progress_percentage, progress_speed);
|
||||
}
|
||||
}
|
||||
SyncUp ();
|
||||
}
|
||||
|
||||
|
||||
|
@ -671,5 +627,35 @@ namespace SparkleLib {
|
|||
Byte[] encoded_bytes = sha1.ComputeHash (bytes);
|
||||
return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
|
||||
}
|
||||
|
||||
|
||||
// Recursively gets a folder's size in bytes
|
||||
private double 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;
|
||||
}
|
||||
|
||||
foreach (DirectoryInfo directory in parent.GetDirectories ())
|
||||
size += CalculateSize (directory);
|
||||
|
||||
} catch (Exception) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,11 @@ using System;
|
|||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
using MonoMac.Foundation;
|
||||
using MonoMac.AppKit;
|
||||
using MonoMac.Foundation;
|
||||
using MonoMac.ObjCRuntime;
|
||||
using MonoMac.WebKit;
|
||||
|
||||
|
||||
namespace SparkleShare {
|
||||
|
||||
public class SparkleAbout : NSWindow {
|
||||
|
@ -54,9 +53,12 @@ namespace SparkleShare {
|
|||
BackingType = NSBackingStore.Buffered;
|
||||
|
||||
CreateAbout ();
|
||||
OrderFrontRegardless ();
|
||||
|
||||
NSApplication.SharedApplication.ActivateIgnoringOtherApps (true);
|
||||
MakeKeyAndOrderFront (this);
|
||||
|
||||
OrderFrontRegardless ();
|
||||
|
||||
Program.UI.UpdateDockIconVisibility ();
|
||||
|
||||
Controller.NewVersionEvent += delegate (string new_version) {
|
||||
|
|
|
@ -44,8 +44,8 @@ namespace SparkleShare {
|
|||
string content_path =
|
||||
Directory.GetParent (System.AppDomain.CurrentDomain.BaseDirectory).ToString ();
|
||||
|
||||
string app_path = Directory.GetParent (content_path).ToString ();
|
||||
string growl_path = Path.Combine (app_path, "Frameworks", "Growl.framework", "Growl");
|
||||
string app_path = Directory.GetParent (content_path).ToString ();
|
||||
string growl_path = Path.Combine (app_path, "Frameworks", "Growl.framework", "Growl");
|
||||
|
||||
|
||||
// Needed for Growl
|
||||
|
@ -54,7 +54,7 @@ namespace SparkleShare {
|
|||
|
||||
|
||||
// Let's use the bundled git first
|
||||
SparkleBackend.DefaultBackend.Path =
|
||||
SparkleGit.Path =
|
||||
Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||
"git", "libexec", "git-core", "git");
|
||||
|
||||
|
@ -68,7 +68,13 @@ namespace SparkleShare {
|
|||
{
|
||||
base.Initialize ();
|
||||
|
||||
this.watcher.Changed += delegate (string path) {
|
||||
this.watcher.Changed += delegate (object sender, SparkleMacWatcherEventArgs args) {
|
||||
string path = args.Path;
|
||||
|
||||
// Don't even bother with paths in .git/
|
||||
if (path.Contains (".git"))
|
||||
return;
|
||||
|
||||
string repo_name;
|
||||
|
||||
if (path.Contains ("/"))
|
||||
|
@ -77,17 +83,20 @@ namespace SparkleShare {
|
|||
repo_name = path;
|
||||
|
||||
// Ignore changes in the root of each subfolder, these
|
||||
// are already handled bu the repository
|
||||
// are already handled by the repository
|
||||
if (Path.GetFileNameWithoutExtension (path).Equals (repo_name))
|
||||
return;
|
||||
|
||||
repo_name = repo_name.Trim ("/".ToCharArray ());
|
||||
FileSystemEventArgs args = new FileSystemEventArgs (WatcherChangeTypes.Changed,
|
||||
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, path), Path.GetFileName (path));
|
||||
FileSystemEventArgs fse_args = new FileSystemEventArgs (
|
||||
WatcherChangeTypes.Changed,
|
||||
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, path),
|
||||
Path.GetFileName (path)
|
||||
);
|
||||
|
||||
foreach (SparkleRepoBase repo in Repositories) {
|
||||
if (repo.Name.Equals (repo_name))
|
||||
repo.OnFileActivity (args);
|
||||
repo.OnFileActivity (fse_args);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -134,7 +134,8 @@ namespace SparkleShare {
|
|||
|
||||
this.progress_indicator = new NSProgressIndicator () {
|
||||
Style = NSProgressIndicatorStyle.Spinning,
|
||||
Frame = new RectangleF (this.web_view.Frame.Width / 2 - 10, this.web_view.Frame.Height / 2 + 10, 20, 20)
|
||||
Frame = new RectangleF (this.web_view.Frame.Width / 2 - 10,
|
||||
this.web_view.Frame.Height / 2 + 10, 20, 20)
|
||||
};
|
||||
|
||||
this.progress_indicator.StartAnimation (this);
|
||||
|
@ -226,15 +227,24 @@ namespace SparkleShare {
|
|||
html = html.Replace ("<!-- $a-color -->", "#0085cf");
|
||||
html = html.Replace ("<!-- $a-hover-color -->", "#009ff8");
|
||||
html = html.Replace ("<!-- $no-buddy-icon-background-image -->",
|
||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "avatar-default.png"));
|
||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||
"Pixmaps","avatar-default.png"));
|
||||
|
||||
html = html.Replace ("<!-- $document-added-background-image -->",
|
||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-added-12.png"));
|
||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||
"Pixmaps", "document-added-12.png"));
|
||||
|
||||
html = html.Replace ("<!-- $document-deleted-background-image -->",
|
||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-deleted-12.png"));
|
||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||
"Pixmaps", "document-deleted-12.png"));
|
||||
|
||||
html = html.Replace ("<!-- $document-edited-background-image -->",
|
||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-edited-12.png"));
|
||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||
"Pixmaps", "document-edited-12.png"));
|
||||
|
||||
html = html.Replace ("<!-- $document-moved-background-image -->",
|
||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath, "Pixmaps", "document-moved-12.png"));
|
||||
"file://" + Path.Combine (NSBundle.MainBundle.ResourcePath,
|
||||
"Pixmaps", "document-moved-12.png"));
|
||||
|
||||
InvokeOnMainThread (delegate {
|
||||
if (this.progress_indicator.Superview == ContentView)
|
||||
|
|
|
@ -14,88 +14,216 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
// Originally taken from:
|
||||
// https://github.com/jesse99/Continuum/blob/master/source/shared/DirectoryWatcher.cs
|
||||
// Modified to use MonoMac and integrate into SparkleShare
|
||||
|
||||
// Copyright (C) 2008 Jesse Jones
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Timers;
|
||||
|
||||
using MonoMac.AppKit;
|
||||
using MonoMac.Foundation;
|
||||
|
||||
namespace SparkleShare {
|
||||
|
||||
public class SparkleMacWatcher {
|
||||
[Serializable]
|
||||
public sealed class SparkleMacWatcherEventArgs : EventArgs {
|
||||
|
||||
public delegate void ChangedEventHandler (string path);
|
||||
public event ChangedEventHandler Changed;
|
||||
public string Path { get; private set; }
|
||||
|
||||
private FileSystemInfo last_changed;
|
||||
private Thread thread;
|
||||
private int poll_count = 0;
|
||||
|
||||
public SparkleMacWatcherEventArgs (string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public sealed class SparkleMacWatcher : IDisposable
|
||||
{
|
||||
public event EventHandler<SparkleMacWatcherEventArgs> Changed;
|
||||
public string Path { get; private set; }
|
||||
|
||||
|
||||
[Flags]
|
||||
[Serializable]
|
||||
private enum FSEventStreamCreateFlags : uint
|
||||
{
|
||||
kFSEventStreamCreateFlagNone = 0x00000000,
|
||||
kFSEventStreamCreateFlagUseCFTypes = 0x00000001,
|
||||
kFSEventStreamCreateFlagNoDefer = 0x00000002,
|
||||
kFSEventStreamCreateFlagWatchRoot = 0x00000004,
|
||||
}
|
||||
|
||||
private DateTime last_found_timestamp;
|
||||
private IntPtr m_stream;
|
||||
private FSEventStreamCallback m_callback; // need to keep a reference around so that it isn't GC'ed
|
||||
private static readonly IntPtr kCFRunLoopDefaultMode = (new NSString ("kCFRunLoopDefaultMode")).Handle;
|
||||
private ulong kFSEventStreamEventIdSinceNow = 0xFFFFFFFFFFFFFFFFUL;
|
||||
|
||||
private delegate void FSEventStreamCallback (
|
||||
IntPtr streamRef,
|
||||
IntPtr clientCallBackInfo,
|
||||
int numEvents,
|
||||
IntPtr eventPaths,
|
||||
IntPtr eventFlags,
|
||||
IntPtr eventIds);
|
||||
|
||||
|
||||
~SparkleMacWatcher ()
|
||||
{
|
||||
Dispose (false);
|
||||
}
|
||||
|
||||
|
||||
public SparkleMacWatcher (string path)
|
||||
{
|
||||
this.thread = new Thread (new ThreadStart (delegate {
|
||||
DateTime timestamp;
|
||||
DirectoryInfo parent = new DirectoryInfo (path);
|
||||
this.last_changed = new DirectoryInfo (path);
|
||||
Path = path;
|
||||
m_callback = DoCallback;
|
||||
|
||||
while (true) {
|
||||
timestamp = this.last_changed.LastWriteTime;
|
||||
GetLastChange (parent);
|
||||
NSString [] s = new NSString [1];
|
||||
s [0] = new NSString (path);
|
||||
NSArray path_p = NSArray.FromNSObjects (s);
|
||||
|
||||
if (DateTime.Compare (this.last_changed.LastWriteTime, timestamp) != 0) {
|
||||
string relative_path = this.last_changed.FullName.Substring (path.Length + 1);
|
||||
m_stream = FSEventStreamCreate ( // note that the stream will always be valid
|
||||
IntPtr.Zero, // allocator
|
||||
m_callback, // callback
|
||||
IntPtr.Zero, // context
|
||||
path_p.Handle, // pathsToWatch
|
||||
kFSEventStreamEventIdSinceNow, // sinceWhen
|
||||
2, // latency (in seconds)
|
||||
FSEventStreamCreateFlags.kFSEventStreamCreateFlagNone); // flags
|
||||
|
||||
if (Changed != null)
|
||||
Changed (relative_path);
|
||||
}
|
||||
FSEventStreamScheduleWithRunLoop (
|
||||
m_stream, // streamRef
|
||||
CFRunLoopGetMain(), // runLoop
|
||||
kCFRunLoopDefaultMode); // runLoopMode
|
||||
|
||||
Thread.Sleep (7500);
|
||||
this.poll_count++;
|
||||
}
|
||||
}));
|
||||
|
||||
this.thread.Start ();
|
||||
}
|
||||
|
||||
|
||||
private void GetLastChange (DirectoryInfo parent)
|
||||
{
|
||||
try {
|
||||
if (DateTime.Compare (parent.LastWriteTime, this.last_changed.LastWriteTime) > 0)
|
||||
this.last_changed = parent;
|
||||
|
||||
foreach (DirectoryInfo info in parent.GetDirectories ()) {
|
||||
if (!info.FullName.Contains ("/.")) {
|
||||
if (DateTime.Compare (info.LastWriteTime, this.last_changed.LastWriteTime) > 0)
|
||||
this.last_changed = info;
|
||||
|
||||
GetLastChange (info);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.poll_count >= 8) {
|
||||
foreach (FileInfo info in parent.GetFiles ()) {
|
||||
if (!info.FullName.Contains ("/.")) {
|
||||
if (DateTime.Compare (info.LastWriteTime, this.last_changed.LastWriteTime) > 0)
|
||||
this.last_changed = info;
|
||||
}
|
||||
}
|
||||
|
||||
this.poll_count = 0;
|
||||
}
|
||||
|
||||
} catch (Exception) {
|
||||
// Don't care...
|
||||
bool started = FSEventStreamStart (m_stream);
|
||||
if (!started) {
|
||||
GC.SuppressFinalize (this);
|
||||
throw new InvalidOperationException ("Failed to start FSEvent stream for " + path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
this.thread.Join ();
|
||||
this.thread.Abort ();
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
|
||||
private void Dispose (bool disposing)
|
||||
{
|
||||
if (m_stream != IntPtr.Zero) {
|
||||
FSEventStreamStop (m_stream);
|
||||
FSEventStreamInvalidate (m_stream);
|
||||
FSEventStreamRelease (m_stream);
|
||||
|
||||
m_stream = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkDirectory (string dir)
|
||||
{
|
||||
DirectoryInfo parent = new DirectoryInfo (dir);
|
||||
|
||||
if (!parent.FullName.Contains ("/.") &&
|
||||
DateTime.Compare (parent.LastWriteTime, this.last_found_timestamp) > 0) {
|
||||
|
||||
last_found_timestamp = parent.LastWriteTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void DoCallback (IntPtr streamRef, IntPtr clientCallBackInfo,
|
||||
int numEvents, IntPtr eventPaths, IntPtr eventFlags, IntPtr eventIds)
|
||||
{
|
||||
int bytes = Marshal.SizeOf (typeof (IntPtr));
|
||||
string [] paths = new string [numEvents];
|
||||
|
||||
for (int i = 0; i < numEvents; ++i) {
|
||||
IntPtr p = Marshal.ReadIntPtr (eventPaths, i * bytes);
|
||||
paths [i] = Marshal.PtrToStringAnsi (p);
|
||||
checkDirectory (paths [i]);
|
||||
}
|
||||
|
||||
var handler = Changed;
|
||||
if (handler != null) {
|
||||
string path = paths [0];
|
||||
path = path.Substring (Path.Length);
|
||||
path = path.Trim ("/".ToCharArray ());
|
||||
handler (this, new SparkleMacWatcherEventArgs (path));
|
||||
}
|
||||
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
|
||||
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||
private extern static IntPtr CFRunLoopGetMain ();
|
||||
|
||||
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||
private extern static IntPtr FSEventStreamCreate (
|
||||
IntPtr allocator,
|
||||
FSEventStreamCallback callback,
|
||||
IntPtr context,
|
||||
IntPtr pathsToWatch,
|
||||
ulong sinceWhen,
|
||||
double latency,
|
||||
FSEventStreamCreateFlags flags);
|
||||
|
||||
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||
private extern static void FSEventStreamScheduleWithRunLoop (
|
||||
IntPtr streamRef,
|
||||
IntPtr runLoop,
|
||||
IntPtr runLoopMode);
|
||||
|
||||
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||
[return: MarshalAs (UnmanagedType.U1)]
|
||||
private extern static bool FSEventStreamStart (
|
||||
IntPtr streamRef);
|
||||
|
||||
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||
private extern static void FSEventStreamStop (
|
||||
IntPtr streamRef);
|
||||
|
||||
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||
private extern static void FSEventStreamInvalidate (
|
||||
IntPtr streamRef);
|
||||
|
||||
[DllImport("/System/Library/Frameworks/CoreServices.framework/CoreServices")]
|
||||
private extern static void FSEventStreamRelease (
|
||||
IntPtr streamRef);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<RootNamespace>SparkleShare</RootNamespace>
|
||||
<AssemblyName>SparkleShare</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<ReleaseVersion>0.8.1</ReleaseVersion>
|
||||
<ReleaseVersion>0.8.2</ReleaseVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -59,7 +59,7 @@
|
|||
<SpecificVersion>False</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="SparkleLib, Version=0.8.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<Reference Include="SparkleLib, Version=0.8.1.0, Culture=neutral, PublicKeyToken=null">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\bin\SparkleLib.dll</HintPath>
|
||||
</Reference>
|
||||
|
|
|
@ -16,6 +16,6 @@ Global
|
|||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
StartupItem = SparkleShare.csproj
|
||||
version = 0.8.1
|
||||
version = 0.8.2
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace SparkleShare {
|
|||
|
||||
public SparkleStatusIconController Controller = new SparkleStatusIconController ();
|
||||
|
||||
// TODO: Fix case
|
||||
private Timer Animation;
|
||||
private int FrameNumber;
|
||||
private string StateText;
|
||||
|
|
|
@ -39,7 +39,5 @@ include $(top_srcdir)/build/build.mk
|
|||
|
||||
bin_SCRIPTS = sparkleshare
|
||||
|
||||
dist_man_MANS = $(top_srcdir)/man/sparkleshare.1
|
||||
|
||||
Applicationsdir = $(datadir)/applications
|
||||
dist_Applications_DATA = sparkleshare.desktop
|
||||
|
|
|
@ -23,7 +23,6 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
|
||||
using Mono.Unix;
|
||||
//using Mono.Unix.Native;
|
||||
using SparkleLib;
|
||||
|
||||
namespace SparkleShare {
|
||||
|
@ -88,10 +87,10 @@ namespace SparkleShare {
|
|||
Console.WriteLine (_("This is free software, and you are welcome to redistribute it "));
|
||||
Console.WriteLine (_("under certain conditions. Please read the GNU GPLv3 for details."));
|
||||
Console.WriteLine (" ");
|
||||
Console.WriteLine (_("SparkleShare automatically syncs Git repositories in "));
|
||||
Console.WriteLine (_("the ~/SparkleShare folder with their remote origins."));
|
||||
Console.WriteLine (_("SparkleShare is a collaboration and sharing tool that is "));
|
||||
Console.WriteLine (_("designed to keep things simple and to stay out of your way."));
|
||||
Console.WriteLine (" ");
|
||||
Console.WriteLine (_("Usage: sparkleshare [start|stop|restart] [OPTION]..."));
|
||||
Console.WriteLine (_("Usage: sparkleshare [start|stop|restart|version] [OPTION]..."));
|
||||
Console.WriteLine (_("Sync SparkleShare folder with remote repositories."));
|
||||
Console.WriteLine (" ");
|
||||
Console.WriteLine (_("Arguments:"));
|
||||
|
@ -107,24 +106,5 @@ namespace SparkleShare {
|
|||
Console.WriteLine (_("SparkleShare " + Defines.VERSION));
|
||||
Environment.Exit (0);
|
||||
}
|
||||
|
||||
|
||||
// Strange magic needed by SetProcessName ()
|
||||
// [DllImport ("libc")]
|
||||
// private static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5);
|
||||
|
||||
|
||||
// Sets the Unix process name to 'sparkleshare' instead of 'mono'
|
||||
/* private static void SetProcessName (string name)
|
||||
{
|
||||
try {
|
||||
if (prctl (15, Encoding.ASCII.GetBytes (name + "\0"), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0)
|
||||
throw new ApplicationException ("Error setting process name: " +
|
||||
Mono.Unix.Native.Stdlib.GetLastError ());
|
||||
|
||||
} catch (EntryPointNotFoundException) {
|
||||
Console.WriteLine ("SetProcessName: Entry point not found");
|
||||
}
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,9 +42,6 @@ namespace SparkleShare {
|
|||
public double ProgressPercentage = 0.0;
|
||||
public string ProgressSpeed = "";
|
||||
|
||||
public event OnQuitWhileSyncingHandler OnQuitWhileSyncing;
|
||||
public delegate void OnQuitWhileSyncingHandler ();
|
||||
|
||||
public event FolderFetchedEventHandler FolderFetched;
|
||||
public delegate void FolderFetchedEventHandler (string [] warnings);
|
||||
|
||||
|
@ -132,10 +129,9 @@ namespace SparkleShare {
|
|||
};
|
||||
|
||||
|
||||
SparkleInviteListener invite_listener = new SparkleInviteListener (1986);
|
||||
SparkleInviteListener invite_listener = new SparkleInviteListener (1987);
|
||||
|
||||
invite_listener.InviteReceived += delegate (SparkleInvite invite) {
|
||||
|
||||
if (OnInvite != null && !FirstRun)
|
||||
OnInvite (invite);
|
||||
};
|
||||
|
@ -303,8 +299,8 @@ namespace SparkleShare {
|
|||
|
||||
if (DateTime.Compare (existing_set.Timestamp, change_set.Timestamp) < 1) {
|
||||
existing_set.FirstTimestamp = existing_set.Timestamp;
|
||||
existing_set.Timestamp = change_set.Timestamp;
|
||||
existing_set.Revision = change_set.Revision;
|
||||
existing_set.Timestamp = change_set.Timestamp;
|
||||
existing_set.Revision = change_set.Revision;
|
||||
|
||||
} else {
|
||||
existing_set.FirstTimestamp = change_set.Timestamp;
|
||||
|
@ -351,37 +347,40 @@ namespace SparkleShare {
|
|||
} else {
|
||||
if (change_set.Edited.Count > 0) {
|
||||
foreach (string file_path in change_set.Edited) {
|
||||
string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
|
||||
change_set.Folder, file_path}.Combine ();
|
||||
|
||||
if (File.Exists (absolute_file_path))
|
||||
event_entry += "<dd class='document edited'><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
|
||||
else
|
||||
event_entry += "<dd class='document edited'>" + file_path + "</dd>";
|
||||
event_entry += "<dd class='document edited'>";
|
||||
|
||||
event_entry += FormatBreadCrumbs (
|
||||
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, change_set.Folder),
|
||||
file_path
|
||||
);
|
||||
|
||||
event_entry += "</dd>";
|
||||
}
|
||||
}
|
||||
|
||||
if (change_set.Added.Count > 0) {
|
||||
foreach (string file_path in change_set.Added) {
|
||||
string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
|
||||
change_set.Folder, file_path}.Combine ();
|
||||
|
||||
if (File.Exists (absolute_file_path))
|
||||
event_entry += "<dd class='document added'><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
|
||||
else
|
||||
event_entry += "<dd class='document added'>" + file_path + "</dd>";
|
||||
event_entry += "<dd class='document added'>";
|
||||
|
||||
event_entry += FormatBreadCrumbs (
|
||||
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, change_set.Folder),
|
||||
file_path
|
||||
);
|
||||
|
||||
event_entry += "</dd>";
|
||||
}
|
||||
}
|
||||
|
||||
if (change_set.Deleted.Count > 0) {
|
||||
foreach (string file_path in change_set.Deleted) {
|
||||
string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
|
||||
change_set.Folder, file_path}.Combine ();
|
||||
|
||||
if (File.Exists (absolute_file_path))
|
||||
event_entry += "<dd class='document deleted'><a href='" + absolute_file_path + "'>" + file_path + "</a></dd>";
|
||||
else
|
||||
event_entry += "<dd class='document deleted'>" + file_path + "</dd>";
|
||||
event_entry += "<dd class='document deleted'>";
|
||||
|
||||
event_entry += FormatBreadCrumbs (
|
||||
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, change_set.Folder),
|
||||
file_path
|
||||
);
|
||||
|
||||
event_entry += "</dd>";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,21 +389,19 @@ namespace SparkleShare {
|
|||
foreach (string file_path in change_set.MovedFrom) {
|
||||
string to_file_path = change_set.MovedTo [i];
|
||||
|
||||
string absolute_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
|
||||
change_set.Folder, file_path}.Combine ();
|
||||
event_entry += "<dd class='document moved'>";
|
||||
event_entry += FormatBreadCrumbs (
|
||||
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, change_set.Folder),
|
||||
file_path
|
||||
);
|
||||
|
||||
string absolute_to_file_path = new string [] {SparkleConfig.DefaultConfig.FoldersPath,
|
||||
change_set.Folder, to_file_path}.Combine ();
|
||||
event_entry += "<br>";
|
||||
event_entry += FormatBreadCrumbs (
|
||||
Path.Combine (SparkleConfig.DefaultConfig.FoldersPath, change_set.Folder),
|
||||
to_file_path
|
||||
);
|
||||
|
||||
if (File.Exists (absolute_file_path))
|
||||
event_entry += "<dd class='document moved'><a href='" + absolute_file_path + "'>" + file_path + "</a><br/>";
|
||||
else
|
||||
event_entry += "<dd class='document moved'>" + file_path + "<br/>";
|
||||
|
||||
if (File.Exists (absolute_to_file_path))
|
||||
event_entry += "<a href='" + absolute_to_file_path + "'>" + to_file_path + "</a></dd>";
|
||||
else
|
||||
event_entry += to_file_path + "</dd>";
|
||||
event_entry += "</dd>";
|
||||
|
||||
i++;
|
||||
}
|
||||
|
@ -620,7 +617,7 @@ namespace SparkleShare {
|
|||
}
|
||||
};
|
||||
|
||||
repo.SyncProgressChanged += delegate (double percentage, string speed) {
|
||||
repo.ProgressChanged += delegate (double percentage, string speed) {
|
||||
ProgressPercentage = percentage;
|
||||
ProgressSpeed = speed;
|
||||
|
||||
|
@ -785,13 +782,6 @@ namespace SparkleShare {
|
|||
}
|
||||
|
||||
|
||||
public bool BackendIsPresent {
|
||||
get {
|
||||
return SparkleBackend.DefaultBackend.IsPresent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Looks up the user's name from the global configuration
|
||||
public string UserName
|
||||
{
|
||||
|
@ -1099,16 +1089,6 @@ namespace SparkleShare {
|
|||
}
|
||||
|
||||
|
||||
// Creates an MD5 hash of input
|
||||
private string GetMD5 (string s)
|
||||
{
|
||||
MD5 md5 = new MD5CryptoServiceProvider ();
|
||||
Byte[] bytes = ASCIIEncoding.Default.GetBytes (s);
|
||||
Byte[] encoded_bytes = md5.ComputeHash (bytes);
|
||||
return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
|
||||
}
|
||||
|
||||
|
||||
// Checks whether there are any folders syncing and
|
||||
// quits if safe
|
||||
public void TryQuit ()
|
||||
|
@ -1118,9 +1098,6 @@ namespace SparkleShare {
|
|||
repo.Status == SyncStatus.SyncDown ||
|
||||
repo.IsBuffering) {
|
||||
|
||||
if (OnQuitWhileSyncing != null)
|
||||
OnQuitWhileSyncing ();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1166,6 +1143,55 @@ namespace SparkleShare {
|
|||
int number = 3 + int.Parse (numbers);
|
||||
return this.tango_palette [number % this.tango_palette.Length];
|
||||
}
|
||||
|
||||
|
||||
// Creates an MD5 hash of input
|
||||
private string GetMD5 (string s)
|
||||
{
|
||||
MD5 md5 = new MD5CryptoServiceProvider ();
|
||||
Byte[] bytes = ASCIIEncoding.Default.GetBytes (s);
|
||||
Byte[] encoded_bytes = md5.ComputeHash (bytes);
|
||||
return BitConverter.ToString (encoded_bytes).ToLower ().Replace ("-", "");
|
||||
}
|
||||
|
||||
|
||||
private string FormatBreadCrumbs (string path_root, string path)
|
||||
{
|
||||
string link = "";
|
||||
string [] crumbs = path.Split (Path.DirectorySeparatorChar);
|
||||
|
||||
int i = 0;
|
||||
string new_path_root = path_root;
|
||||
bool previous_was_folder = false;
|
||||
foreach (string crumb in crumbs) {
|
||||
|
||||
if (string.IsNullOrEmpty (crumb))
|
||||
continue;
|
||||
|
||||
string crumb_path = Path.Combine (new_path_root, crumb);
|
||||
|
||||
if (Directory.Exists (crumb_path)) {
|
||||
link += "<a href='" + crumb_path + "'>" + crumb + Path.DirectorySeparatorChar + "</a>";
|
||||
previous_was_folder = true;
|
||||
|
||||
} else if (File.Exists (crumb_path)) {
|
||||
link += "<a href='" + crumb_path + "'>" + crumb + "</a>";
|
||||
previous_was_folder = false;
|
||||
|
||||
} else {
|
||||
if (i > 0 && !previous_was_folder)
|
||||
link += Path.DirectorySeparatorChar;
|
||||
|
||||
link += crumb;
|
||||
previous_was_folder = false;
|
||||
}
|
||||
|
||||
new_path_root = Path.Combine (new_path_root, crumb);
|
||||
i++;
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -60,7 +60,37 @@ namespace SparkleShare {
|
|||
|
||||
public SparkleInvite (string xml_file_path)
|
||||
{
|
||||
// TODO
|
||||
XmlDocument xml_document = new XmlDocument ();
|
||||
XmlNode node;
|
||||
|
||||
string host = "", path = "", token = "";
|
||||
|
||||
try {
|
||||
xml_document.Load (xml_file_path);
|
||||
|
||||
node = xml_document.SelectSingleNode ("/sparkleshare/invite/host/text()");
|
||||
if (node != null) { host = node.Value; }
|
||||
|
||||
node = xml_document.SelectSingleNode ("/sparkleshare/invite/path/text()");
|
||||
if (node != null) { path = node.Value; }
|
||||
|
||||
node = xml_document.SelectSingleNode ("/sparkleshare/invite/token/text()");
|
||||
if (node != null) { token = node.Value; }
|
||||
|
||||
} catch (XmlException e) {
|
||||
SparkleHelpers.DebugInfo ("Invite", "Invalid XML: " + e.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (path.StartsWith ("/"))
|
||||
path = path.Substring (1);
|
||||
|
||||
if (!host.EndsWith ("/"))
|
||||
host = host + "/";
|
||||
|
||||
FullAddress = new Uri ("ssh://" + host + path);
|
||||
Token = token;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,9 +198,8 @@ namespace SparkleShare {
|
|||
|
||||
XmlDocument xml_document = new XmlDocument ();
|
||||
XmlNode node;
|
||||
string host = "";
|
||||
string path = "";
|
||||
string token = "";
|
||||
|
||||
string host = "", path = "", token = "";
|
||||
|
||||
try {
|
||||
xml_document.LoadXml (invite_xml);
|
||||
|
@ -185,7 +214,7 @@ namespace SparkleShare {
|
|||
if (node != null) { token = node.Value; }
|
||||
|
||||
} catch (XmlException e) {
|
||||
SparkleHelpers.DebugInfo ("Invite", "Not valid XML: " + received_message + " " + e.Message);
|
||||
SparkleHelpers.DebugInfo ("Invite", "Invalid XML: " + received_message + " " + e.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,56 +16,83 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace SparkleShare {
|
||||
|
||||
public class SparklePlugin {
|
||||
|
||||
public string Name;
|
||||
public string Description;
|
||||
public string ImagePath;
|
||||
public string Backend;
|
||||
public string Name {
|
||||
get {
|
||||
return GetValue ("info", "name");
|
||||
}
|
||||
}
|
||||
|
||||
public string Address;
|
||||
public string AddressExample;
|
||||
public string Path;
|
||||
public string PathExample;
|
||||
public string Description {
|
||||
get {
|
||||
return GetValue ("info", "description");
|
||||
}
|
||||
}
|
||||
|
||||
public string ImagePath {
|
||||
get {
|
||||
return System.IO.Path.Combine (
|
||||
this.plugin_directory,
|
||||
GetValue ("info", "icon")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public string Backend {
|
||||
get {
|
||||
return GetValue ("info", "backend");
|
||||
}
|
||||
}
|
||||
|
||||
public string Address {
|
||||
get {
|
||||
return GetValue ("address", "value");
|
||||
}
|
||||
}
|
||||
|
||||
public string AddressExample {
|
||||
get {
|
||||
return GetValue ("address", "example");
|
||||
}
|
||||
}
|
||||
|
||||
public string Path {
|
||||
get {
|
||||
return GetValue ("path", "value");
|
||||
}
|
||||
}
|
||||
|
||||
public string PathExample {
|
||||
get {
|
||||
return GetValue ("path", "example");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private XmlDocument xml = new XmlDocument ();
|
||||
private string plugin_directory;
|
||||
|
||||
public SparklePlugin (string plugin_path)
|
||||
{
|
||||
string plugin_directory = System.IO.Path.GetDirectoryName (plugin_path);
|
||||
this.plugin_directory = System.IO.Path.GetDirectoryName (plugin_path);
|
||||
this.xml.Load (plugin_path);
|
||||
}
|
||||
|
||||
XmlDocument xml = new XmlDocument ();
|
||||
xml.Load (plugin_path);
|
||||
|
||||
XmlNode node;
|
||||
private string GetValue (string a, string b)
|
||||
{
|
||||
XmlNode node = this.xml.SelectSingleNode (
|
||||
"/sparkleshare/plugin/" + a + "/" + b + "/text()");
|
||||
|
||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/info/name/text()");
|
||||
if (node != null) { Name = node.Value; }
|
||||
|
||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/info/description/text()");
|
||||
if (node != null) { Description = node.Value; }
|
||||
|
||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/info/icon/text()");
|
||||
if (node != null) { ImagePath = System.IO.Path.Combine (plugin_directory, node.Value); }
|
||||
|
||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/info/backend/text()");
|
||||
if (node != null) { Backend = node.Value; }
|
||||
|
||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/address/value/text()");
|
||||
if (node != null) { Address = node.Value; }
|
||||
|
||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/address/example/text()");
|
||||
if (node != null) { AddressExample = node.Value; }
|
||||
|
||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/path/value/text()");
|
||||
if (node != null) { Path = node.Value; }
|
||||
|
||||
node = xml.SelectSingleNode ("/sparkleshare/plugin/path/example/text()");
|
||||
if (node != null) { PathExample = node.Value; }
|
||||
if (node != null)
|
||||
return node.Value;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,12 +33,11 @@ namespace SparkleShare {
|
|||
|
||||
public SparkleStatusIconController Controller = new SparkleStatusIconController ();
|
||||
|
||||
// TODO: fix case
|
||||
private Timer Animation;
|
||||
private Gdk.Pixbuf [] AnimationFrames;
|
||||
private int FrameNumber;
|
||||
private string StateText;
|
||||
private Menu Menu;
|
||||
private Timer animation;
|
||||
private Gdk.Pixbuf [] animation_frames;
|
||||
private int frame_number;
|
||||
private string state_text;
|
||||
private Menu menu;
|
||||
private MenuItem quit_item;
|
||||
|
||||
#if HAVE_APP_INDICATOR
|
||||
|
@ -56,8 +55,8 @@ namespace SparkleShare {
|
|||
|
||||
public SparkleStatusIcon ()
|
||||
{
|
||||
AnimationFrames = CreateAnimationFrames ();
|
||||
Animation = CreateAnimation ();
|
||||
CreateAnimationFrames ();
|
||||
CreateAnimation ();
|
||||
|
||||
#if HAVE_APP_INDICATOR
|
||||
this.indicator = new ApplicationIndicator ("sparkleshare",
|
||||
|
@ -70,13 +69,13 @@ namespace SparkleShare {
|
|||
|
||||
this.status_icon.Activate += ShowMenu; // Primary mouse button click
|
||||
this.status_icon.PopupMenu += ShowMenu; // Secondary mouse button click
|
||||
this.status_icon.Pixbuf = AnimationFrames [0];
|
||||
this.status_icon.Pixbuf = this.animation_frames [0];
|
||||
#endif
|
||||
|
||||
if (Controller.Folders.Length == 0)
|
||||
StateText = _("Welcome to SparkleShare!");
|
||||
this.state_text = _("Welcome to SparkleShare!");
|
||||
else
|
||||
StateText = _("Up to date") + Controller.FolderSize;
|
||||
this.state_text = _("Up to date") + Controller.FolderSize;
|
||||
|
||||
CreateMenu ();
|
||||
|
||||
|
@ -85,7 +84,7 @@ namespace SparkleShare {
|
|||
Application.Invoke (delegate {
|
||||
if (this.quit_item != null) {
|
||||
this.quit_item.Sensitive = quit_item_enabled;
|
||||
Menu.ShowAll ();
|
||||
this.menu.ShowAll ();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -95,17 +94,17 @@ namespace SparkleShare {
|
|||
switch (state) {
|
||||
case IconState.Idle:
|
||||
|
||||
Animation.Stop ();
|
||||
this.animation.Stop ();
|
||||
|
||||
if (Controller.Folders.Length == 0)
|
||||
StateText = _("Welcome to SparkleShare!");
|
||||
this.state_text = _("Welcome to SparkleShare!");
|
||||
else
|
||||
StateText = _("Up to date") + Controller.FolderSize;
|
||||
this.state_text = _("Up to date") + Controller.FolderSize;
|
||||
|
||||
#if HAVE_APP_INDICATOR
|
||||
this.indicator.IconName = "process-syncing-sparkleshare-i";
|
||||
#else
|
||||
this.status_icon.Pixbuf = AnimationFrames [0];
|
||||
this.status_icon.Pixbuf = this.animation_frames [0];
|
||||
#endif
|
||||
|
||||
UpdateStateText ();
|
||||
|
@ -115,22 +114,22 @@ namespace SparkleShare {
|
|||
|
||||
case IconState.Syncing:
|
||||
|
||||
StateText = _("Syncing… ") +
|
||||
this.state_text = _("Syncing… ") +
|
||||
Controller.ProgressPercentage + "% " +
|
||||
Controller.ProgressSpeed;
|
||||
|
||||
UpdateStateText ();
|
||||
|
||||
if (!Animation.Enabled)
|
||||
Animation.Start ();
|
||||
if (!this.animation.Enabled)
|
||||
this.animation.Start ();
|
||||
|
||||
break;
|
||||
|
||||
case IconState.Error:
|
||||
|
||||
Animation.Stop ();
|
||||
this.animation.Stop ();
|
||||
|
||||
StateText = _("Not everything is synced");
|
||||
this.state_text = _("Not everything is synced");
|
||||
UpdateStateText ();
|
||||
CreateMenu ();
|
||||
|
||||
|
@ -143,7 +142,7 @@ namespace SparkleShare {
|
|||
break;
|
||||
}
|
||||
|
||||
Menu.ShowAll ();
|
||||
this.menu.ShowAll ();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -151,47 +150,43 @@ namespace SparkleShare {
|
|||
|
||||
// Slices up the graphic that contains the
|
||||
// animation frames.
|
||||
private Gdk.Pixbuf [] CreateAnimationFrames ()
|
||||
private void CreateAnimationFrames ()
|
||||
{
|
||||
Gdk.Pixbuf [] animation_frames = new Gdk.Pixbuf [5];
|
||||
this.animation_frames = new Gdk.Pixbuf [5];
|
||||
Gdk.Pixbuf frames_pixbuf = SparkleUIHelpers.GetIcon ("process-syncing-sparkleshare", 24);
|
||||
|
||||
for (int i = 0; i < animation_frames.Length; i++)
|
||||
for (int i = 0; i < this.animation_frames.Length; i++)
|
||||
animation_frames [i] = new Gdk.Pixbuf (frames_pixbuf, (i * 24), 0, 24, 24);
|
||||
|
||||
return animation_frames;
|
||||
}
|
||||
|
||||
|
||||
// Creates the Animation that handles the syncing animation
|
||||
private Timer CreateAnimation ()
|
||||
// Creates the animation that handles the syncing animation
|
||||
private void CreateAnimation ()
|
||||
{
|
||||
FrameNumber = 0;
|
||||
this.frame_number = 0;
|
||||
|
||||
Timer Animation = new Timer () {
|
||||
this.animation = new Timer () {
|
||||
Interval = 35
|
||||
};
|
||||
|
||||
Animation.Elapsed += delegate {
|
||||
if (FrameNumber < AnimationFrames.Length - 1)
|
||||
FrameNumber++;
|
||||
this.animation.Elapsed += delegate {
|
||||
if (this.frame_number < this.animation_frames.Length - 1)
|
||||
this.frame_number++;
|
||||
else
|
||||
FrameNumber = 0;
|
||||
this.frame_number = 0;
|
||||
|
||||
string icon_name = "process-syncing-sparkleshare-";
|
||||
for (int i = 0; i <= FrameNumber; i++)
|
||||
for (int i = 0; i <= this.frame_number; i++)
|
||||
icon_name += "i";
|
||||
|
||||
Application.Invoke (delegate {
|
||||
#if HAVE_APP_INDICATOR
|
||||
this.indicator.IconName = icon_name;
|
||||
#else
|
||||
this.status_icon.Pixbuf = AnimationFrames [FrameNumber];
|
||||
this.status_icon.Pixbuf = this.animation_frames [this.frame_number];
|
||||
#endif
|
||||
});
|
||||
};
|
||||
|
||||
return Animation;
|
||||
}
|
||||
|
||||
|
||||
|
@ -199,15 +194,15 @@ namespace SparkleShare {
|
|||
// user clicks the status icon
|
||||
public void CreateMenu ()
|
||||
{
|
||||
Menu = new Menu ();
|
||||
this.menu = new Menu ();
|
||||
|
||||
// The menu item showing the status and size of the SparkleShare folder
|
||||
MenuItem status_menu_item = new MenuItem (StateText) {
|
||||
MenuItem status_menu_item = new MenuItem (this.state_text) {
|
||||
Sensitive = false
|
||||
};
|
||||
|
||||
Menu.Add (status_menu_item);
|
||||
Menu.Add (new SeparatorMenuItem ());
|
||||
this.menu.Add (status_menu_item);
|
||||
this.menu.Add (new SeparatorMenuItem ());
|
||||
|
||||
ImageMenuItem folder_item = new SparkleMenuItem ("SparkleShare"){
|
||||
Image = new Image (SparkleUIHelpers.GetIcon ("folder-sparkleshare", 16))
|
||||
|
@ -217,7 +212,7 @@ namespace SparkleShare {
|
|||
Program.Controller.OpenSparkleShareFolder ();
|
||||
};
|
||||
|
||||
Menu.Add (folder_item);
|
||||
this.menu.Add (folder_item);
|
||||
|
||||
if (Program.Controller.Folders.Count > 0) {
|
||||
|
||||
|
@ -239,7 +234,7 @@ namespace SparkleShare {
|
|||
};
|
||||
|
||||
subfolder_item.Activated += OpenFolderDelegate (folder_name);
|
||||
Menu.Add (subfolder_item);
|
||||
this.menu.Add (subfolder_item);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -247,10 +242,10 @@ namespace SparkleShare {
|
|||
Sensitive = false
|
||||
};
|
||||
|
||||
Menu.Add (no_folders_item);
|
||||
this.menu.Add (no_folders_item);
|
||||
}
|
||||
|
||||
Menu.Add (new SeparatorMenuItem ());
|
||||
this.menu.Add (new SeparatorMenuItem ());
|
||||
|
||||
// Opens the wizard to add a new remote folder
|
||||
MenuItem sync_item = new MenuItem (_("Add Hosted Project…"));
|
||||
|
@ -274,8 +269,8 @@ namespace SparkleShare {
|
|||
});
|
||||
};
|
||||
|
||||
Menu.Add (sync_item);
|
||||
Menu.Add (new SeparatorMenuItem ());
|
||||
this.menu.Add (sync_item);
|
||||
this.menu.Add (new SeparatorMenuItem ());
|
||||
|
||||
MenuItem recent_events_item = new MenuItem (_("Open Recent Events"));
|
||||
|
||||
|
@ -291,7 +286,7 @@ namespace SparkleShare {
|
|||
});
|
||||
};
|
||||
|
||||
Menu.Add (recent_events_item);
|
||||
this.menu.Add (recent_events_item);
|
||||
|
||||
MenuItem notify_item;
|
||||
|
||||
|
@ -305,8 +300,8 @@ namespace SparkleShare {
|
|||
CreateMenu ();
|
||||
};
|
||||
|
||||
Menu.Add (notify_item);
|
||||
Menu.Add (new SeparatorMenuItem ());
|
||||
this.menu.Add (notify_item);
|
||||
this.menu.Add (new SeparatorMenuItem ());
|
||||
|
||||
// A menu item that takes the user to http://www.sparkleshare.org/
|
||||
MenuItem about_item = new MenuItem (_("About SparkleShare"));
|
||||
|
@ -321,8 +316,8 @@ namespace SparkleShare {
|
|||
});
|
||||
};
|
||||
|
||||
Menu.Add (about_item);
|
||||
Menu.Add (new SeparatorMenuItem ());
|
||||
this.menu.Add (about_item);
|
||||
this.menu.Add (new SeparatorMenuItem ());
|
||||
|
||||
// A menu item that quits the application
|
||||
this.quit_item = new MenuItem (_("Quit")) {
|
||||
|
@ -333,11 +328,11 @@ namespace SparkleShare {
|
|||
Program.Controller.Quit ();
|
||||
};
|
||||
|
||||
Menu.Add (this.quit_item);
|
||||
Menu.ShowAll ();
|
||||
this.menu.Add (this.quit_item);
|
||||
this.menu.ShowAll ();
|
||||
|
||||
#if HAVE_APP_INDICATOR
|
||||
this.indicator.Menu = Menu;
|
||||
this.indicator.Menu = this.menu;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -354,15 +349,15 @@ namespace SparkleShare {
|
|||
|
||||
public void UpdateStateText ()
|
||||
{
|
||||
((Menu.Children [0] as MenuItem).Child as Label).Text = StateText;
|
||||
Menu.ShowAll ();
|
||||
((this.menu.Children [0] as MenuItem).Child as Label).Text = this.state_text;
|
||||
this.menu.ShowAll ();
|
||||
}
|
||||
|
||||
#if !HAVE_APP_INDICATOR
|
||||
// Makes the menu visible
|
||||
private void ShowMenu (object o, EventArgs args)
|
||||
{
|
||||
Menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime);
|
||||
this.menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -69,12 +69,9 @@ namespace SparkleShare {
|
|||
Setup = new SparkleSetup ();
|
||||
Setup.Controller.ShowSetupPage ();
|
||||
}
|
||||
|
||||
Program.Controller.OnQuitWhileSyncing += delegate {
|
||||
// TODO: Pop up a warning when quitting whilst syncing
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Runs the application
|
||||
public void Run ()
|
||||
{
|
||||
|
|
|
@ -42,7 +42,7 @@ stop() {
|
|||
rm -f ${pidfile}
|
||||
echo "Done."
|
||||
else
|
||||
echo "SparkleShare is not running, removing stale pid file."
|
||||
echo "SparkleShare is not running, removing stale pid file..."
|
||||
rm -f ${pidfile}
|
||||
fi
|
||||
else
|
||||
|
@ -64,14 +64,10 @@ case $1 in
|
|||
help|--help|-h)
|
||||
mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --help
|
||||
;;
|
||||
-d|--disable-gui)
|
||||
mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --disable-gui
|
||||
;;
|
||||
-v|--version)
|
||||
version|--version|-v)
|
||||
mono "@expanded_libdir@/@PACKAGE@/SparkleShare.exe" --version
|
||||
;;
|
||||
*)
|
||||
echo "Usage: sparkleshare {start|stop|restart|help}"
|
||||
echo "Usage: sparkleshare {start|stop|restart|help|version}"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
m4_define([sparkleshare_version],
|
||||
[0.8.1])
|
||||
[0.8.2])
|
||||
|
||||
m4_define([sparkleshare_asm_version],
|
||||
[0.8.1])
|
||||
[0.8.2])
|
||||
|
||||
AC_PREREQ([2.54])
|
||||
AC_INIT([SparkleShare], sparkleshare_version)
|
||||
|
@ -154,7 +154,6 @@ data/Makefile
|
|||
data/icons/Makefile
|
||||
data/html/Makefile
|
||||
data/plugins/Makefile
|
||||
help/Makefile
|
||||
SparkleLib/AssemblyInfo.cs
|
||||
SparkleLib/Defines.cs
|
||||
SparkleLib/Makefile
|
||||
|
@ -176,7 +175,6 @@ Configuration:
|
|||
Build Gtk+ UI : ${enable_gtkui}
|
||||
Nautilus 2.x plugin : ${have_nautilus2_python}
|
||||
Nautilus 3.x plugin : ${have_nautilus3_python}
|
||||
User Help : ${enable_user_help} (requires gnome-doc-utils >= 0.17.3)
|
||||
|
||||
"
|
||||
|
||||
|
|
|
@ -139,6 +139,7 @@
|
|||
|
||||
a:hover {
|
||||
color: <!-- $a-hover-color -->;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.event-timestamp {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
<page xmlns="http://projectmallard.org/1.0/"
|
||||
xmlns:e="http://projectmallard.org/experimental/"
|
||||
type="topic" style="task"
|
||||
id="accounts">
|
||||
|
||||
<info>
|
||||
<link type="guide" xref="index#account"/>
|
||||
<link type="seealso" xref=""/>
|
||||
<desc>Add the location of your remote folders.</desc>
|
||||
<revision pkgversion="0.1" version="0.1" date="2010-08-9" status="stub"/>
|
||||
<credit type="author">
|
||||
<name>Paul Cutler</name>
|
||||
<email>pcutler@gnome.org</email>
|
||||
</credit>
|
||||
<!--
|
||||
<copyright>
|
||||
<year>2010</year>
|
||||
<name>GNOME Documentation Project</name>
|
||||
</copyright>
|
||||
-->
|
||||
<include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude"/>
|
||||
</info>
|
||||
|
||||
<title>Account Setup</title>
|
||||
|
||||
<p>Insert how to setup your accounts here)
|
||||
</p>
|
||||
|
||||
<p>Insert more help here, if needed.
|
||||
</p>
|
||||
|
||||
</page>
|
|
@ -1,32 +0,0 @@
|
|||
<page xmlns="http://projectmallard.org/1.0/"
|
||||
xmlns:e="http://projectmallard.org/experimental/"
|
||||
type="guide" style="2column"
|
||||
id="advanced">
|
||||
|
||||
<info>
|
||||
<link type="guide" xref="index#advanced"/>
|
||||
<desc>Get help for advanced actions.</desc>
|
||||
<revision pkgversion="0.1" version="0.1" date="2010-08-29" status="draft"/>
|
||||
<credit type="author">
|
||||
<name>Paul Cutler</name>
|
||||
<email>pcutler@gnome.org</email>
|
||||
</credit>
|
||||
<!--
|
||||
<copyright>
|
||||
<year>2010</year>
|
||||
<name>GNOME Documentation Project</name>
|
||||
</copyright>
|
||||
-->
|
||||
<include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude"/>
|
||||
</info>
|
||||
|
||||
<title>Advanced Options and Help</title>
|
||||
|
||||
<section id="tbd" style="2column">
|
||||
<info>
|
||||
<title type="link">TBD</title>
|
||||
</info>
|
||||
<title>TBD</title>
|
||||
</section>
|
||||
|
||||
</page>
|
|
@ -1,40 +0,0 @@
|
|||
<page xmlns="http://projectmallard.org/1.0/"
|
||||
xmlns:e="http://projectmallard.org/experimental/"
|
||||
type="guide"
|
||||
id="index">
|
||||
|
||||
<info>
|
||||
<revision pkgversion="0.1" version="0.1" date="2010-08-29"
|
||||
status="incomplete"/>
|
||||
<credit type="author">
|
||||
<name>Paul Cutler</name>
|
||||
<email>pcutler@gnome.org</email>
|
||||
</credit>
|
||||
<!--
|
||||
<copyright>
|
||||
<year>2010</year>
|
||||
<name>GNOME Documentation Project</name>
|
||||
</copyright>
|
||||
-->
|
||||
<include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude" />
|
||||
</info>
|
||||
|
||||
<title>SparkleShare</title>
|
||||
|
||||
<section id="account" style="2column">
|
||||
<title>Account Setup</title>
|
||||
</section>
|
||||
|
||||
<section id="share" style="2column">
|
||||
<title>Sync and Share Files</title>
|
||||
</section>
|
||||
|
||||
<section id="advanced" style="2column">
|
||||
<title>Advanced options and help</title>
|
||||
</section>
|
||||
|
||||
<section id="problems">
|
||||
<title>Common Problems</title>
|
||||
</section>
|
||||
|
||||
</page>
|
|
@ -1,42 +0,0 @@
|
|||
<page xmlns="http://projectmallard.org/1.0/"
|
||||
type="topic"
|
||||
id="introduction">
|
||||
|
||||
<info>
|
||||
<link type="guide" xref="index"/>
|
||||
<revision pkgversion="0.1" version="0.1" date="2010-08-29" status="draft"/>
|
||||
<desc>
|
||||
Introduction to <app>SparkleShare</app>.
|
||||
</desc>
|
||||
<credit type="author">
|
||||
<name>Paul Cutler</name>
|
||||
<email>pcutler@gnome.org</email>
|
||||
</credit>
|
||||
<!--
|
||||
<copyright>
|
||||
<year>2010</year>
|
||||
<name>GNOME Documentation Project</name>
|
||||
</copyright>
|
||||
-->
|
||||
<include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude" />
|
||||
</info>
|
||||
|
||||
<title>Introduction</title>
|
||||
|
||||
<p>
|
||||
<app>SparkleShare</app> is an application that allows you to easily
|
||||
sync and share your files and folders. SparkeShare uses the
|
||||
distributed version control system <app>Git</app> to keep a record
|
||||
of all the changes in your files, making it easy to easily go back
|
||||
to an earlier version of the file if you make a mistake.
|
||||
</p>
|
||||
|
||||
<figure>
|
||||
<title><gui>SparkleShare</gui> screenshot</title>
|
||||
<desc><app>SparkleShare</app></desc>
|
||||
<media type="image" src="figures/sparkleshare.png" mime="image/png" style="right">
|
||||
<p><app>Sparkleshare</app></p>
|
||||
</media>
|
||||
</figure>
|
||||
|
||||
</page>
|
|
@ -1,9 +0,0 @@
|
|||
<license xmlns="http://projectmallard.org/1.0/"
|
||||
href="http://creativecommons.org/licenses/by-sa/3.0/">
|
||||
<p>This work is licensed under a
|
||||
<link href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons
|
||||
Attribution-Share Alike 3.0 Unported License</link>.</p>
|
||||
<p>As a special exception, the copyright holders give you permission to copy,
|
||||
modify, and distribute the example code contained in this document under the
|
||||
terms of your choosing, without restriction.</p>
|
||||
</license>
|
|
@ -1,32 +0,0 @@
|
|||
<page xmlns="http://projectmallard.org/1.0/"
|
||||
xmlns:e="http://projectmallard.org/experimental/"
|
||||
type="topic" style="task"
|
||||
id="share">
|
||||
|
||||
<info>
|
||||
<link type="guide" xref="index#share"/>
|
||||
<link type="seealso" xref=""/>
|
||||
<desc>Sync and share your folders and files.</desc>
|
||||
<revision pkgversion="1.6" version="0.1" date="2010-07-11" status="draft"/>
|
||||
<credit type="author">
|
||||
<name>Paul Cutler</name>
|
||||
<email>pcutler@gnome.org</email>
|
||||
</credit>
|
||||
<!--
|
||||
<copyright>
|
||||
<year>2010</year>
|
||||
<name>GNOME Documentation Project</name>
|
||||
</copyright>
|
||||
-->
|
||||
<include href="legal.xml" xmlns="http://www.w3.org/2001/XInclude"/>
|
||||
</info>
|
||||
|
||||
<title>Sync and share your files and folders</title>
|
||||
|
||||
<p>Insert help here.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
</p>
|
||||
|
||||
</page>
|
|
@ -1,17 +0,0 @@
|
|||
if HAVE_GNOME_DOC_UTILS
|
||||
include $(top_srcdir)/gnome-doc-utils.make
|
||||
|
||||
DOC_ID = sparkleshare
|
||||
|
||||
DOC_INCLUDES = legal.xml
|
||||
|
||||
DOC_PAGES = account-creation.page \
|
||||
advanced.page \
|
||||
index.page \
|
||||
introduction.page \
|
||||
share.page
|
||||
|
||||
DOC_LINGUAS =
|
||||
|
||||
dist-hook: doc-dist-hook
|
||||
endif
|
|
@ -1,36 +0,0 @@
|
|||
.TH sparkleshare 1 "August 16, 2010" "version 0.2" "USER COMMANDS"
|
||||
.SH NAME
|
||||
sparkleshare \- sharing work made easy
|
||||
.SH SYNOPSIS
|
||||
.B sparkleshare
|
||||
[start|stop|restart|help]
|
||||
.SH DESCRIPTION
|
||||
A file sharing system for the desktop that retains a full history of
|
||||
changes made, and allows work to be sychronized across many systems.
|
||||
Based on the underlying `git' version control system, sparkleshare is
|
||||
fast and secure, but the interface is straightforward enough for all
|
||||
to use.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
start
|
||||
Start the sparkleshare system, presenting an introductory dialog if
|
||||
this is the first time that it has been run.
|
||||
.TP
|
||||
stop
|
||||
Stop sparkleshare, halting all current file sharing and no longer watch
|
||||
for changes in the configured shares.
|
||||
.TP
|
||||
restart
|
||||
Restart sparkleshare.
|
||||
.SH RETURN VALUES
|
||||
Currently sparkleshare only ever returns 0 on exit.
|
||||
.SH FILES
|
||||
.TP
|
||||
~/SparkleShare
|
||||
Directories set up to be shared are placed under this directory.
|
||||
.SH BUGS
|
||||
SparkleShare is currently under development, it is likely that there
|
||||
are a number of bugs present in the system. Since the underlying
|
||||
file sharing is simply based on `git', even if SparkleShare itself fails,
|
||||
the data is retrievable in an open format. On-disk corruption is
|
||||
extremely unlikely.
|
Loading…
Reference in a new issue