Fix autostart because pid already exists even though program is not running
This commit is contained in:
parent
01647a6e4e
commit
f377e03790
64
SparkleShare
Normal file
64
SparkleShare
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
pidfile=/tmp/sparkleshare/sparkleshare.pid
|
||||||
|
|
||||||
|
# Create a directory to save the pid to
|
||||||
|
if [[ "$1" == "start" ]]; then
|
||||||
|
if [ -e "${pidfile}" ]; then
|
||||||
|
sparklepid=`cat ${pidfile}`
|
||||||
|
if [ -n "`ps -p ${sparklepid} | grep ${sparklepid}`" ]
|
||||||
|
then
|
||||||
|
echo "SparkleShare is already running"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "SparkleShare stale pid file found, starting a new instance"
|
||||||
|
rm -f $pidfile
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Starting SparkleShare..."
|
||||||
|
mkdir -p /tmp/sparkleshare/
|
||||||
|
# Start SparkleShare in the background and save the pid
|
||||||
|
mono /usr/local/share/sparkleshare/SparkleShare.exe $2 &
|
||||||
|
PID=$!
|
||||||
|
echo $PID > /tmp/sparkleshare/sparkleshare.pid
|
||||||
|
echo " Done."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$1" == "stop" ]]; then
|
||||||
|
if [ -e "/tmp/sparkleshare/sparkleshare.pid" ]; then
|
||||||
|
echo -n "Stopping SparkleShare..."
|
||||||
|
kill `cat /tmp/sparkleshare/sparkleshare.pid`
|
||||||
|
rm -f /tmp/sparkleshare/sparkleshare.pid
|
||||||
|
echo " Done."
|
||||||
|
else
|
||||||
|
echo "SparkleShare isn't running."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$1" == "restart" ]]; then
|
||||||
|
if [ -e "/tmp/sparkleshare/sparkleshare.pid" ]; then
|
||||||
|
echo -n "Stopping SparkleShare..."
|
||||||
|
kill `cat /tmp/sparkleshare/sparkleshare.pid`
|
||||||
|
rm -f /tmp/sparkleshare/sparkleshare.pid
|
||||||
|
echo " Done."
|
||||||
|
else
|
||||||
|
echo "SparkleShare isn't running."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e "/tmp/sparkleshare/sparkleshare.pid" ]; then
|
||||||
|
echo "SparkleShare is already running."
|
||||||
|
else
|
||||||
|
echo -n "Starting SparkleShare..."
|
||||||
|
|
||||||
|
# Start SparkleShare in the background and save the pid
|
||||||
|
mono /usr/local/share/sparkleshare/SparkleShare.exe $2 &
|
||||||
|
PID=$!
|
||||||
|
echo $PID > /tmp/sparkleshare/sparkleshare.pid
|
||||||
|
echo " Done."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$1" == "--help" ]]; then
|
||||||
|
mono /usr/local/share/sparkleshare/SparkleShare.exe --help
|
||||||
|
fi
|
|
@ -1,49 +0,0 @@
|
||||||
// SparkleShare, an instant update workflow to Git.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// 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 Gtk;
|
|
||||||
using Notifications;
|
|
||||||
using SparkleShare;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
public class SparkleBubble : Notification {
|
|
||||||
|
|
||||||
public SparkleBubble (string Title, string Subtext) : base (Title, Subtext) {
|
|
||||||
|
|
||||||
Timeout = 4500;
|
|
||||||
Urgency = Urgency.Low;
|
|
||||||
IconName = "folder-sparkleshare";
|
|
||||||
AttachToStatusIcon (SparkleUI.NotificationIcon);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks whether the system allows adding buttons to a notification,
|
|
||||||
// prevents error messages in Ubuntu.
|
|
||||||
new public void AddAction (string Action, string Label,
|
|
||||||
ActionHandler Handler) {
|
|
||||||
|
|
||||||
bool CanHaveButtons =
|
|
||||||
(System.Array.IndexOf (Notifications.Global.Capabilities,
|
|
||||||
"actions") > -1);
|
|
||||||
if (CanHaveButtons)
|
|
||||||
base.AddAction(Action, Label, Handler);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
// SparkleShare, an instant update workflow to Git.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// 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 Notifications;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
public class SparkleBubble : Notification {
|
|
||||||
|
|
||||||
public SparkleBubble (string Title, string Subtext) : base (Title, Subtext) {
|
|
||||||
Timeout = 4500;
|
|
||||||
Urgency = Urgency.Low;
|
|
||||||
Show ();
|
|
||||||
// StatusIcon = SparkleUI.NotificationIcon; // Doesn't work for some reason :(
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,204 +0,0 @@
|
||||||
// SparkleShare, an instant update workflow to Git.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// 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 Gtk;
|
|
||||||
using Mono.Unix;
|
|
||||||
using SparkleShare;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
// A dialog where the user can enter a folder
|
|
||||||
// name and url to sync changes with
|
|
||||||
public class SparkleDialog : Window {
|
|
||||||
|
|
||||||
// Short alias for the translations
|
|
||||||
public static string _ (string s)
|
|
||||||
{
|
|
||||||
return Catalog.GetString (s);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Button AddButton;
|
|
||||||
private ComboBoxEntry RemoteUrlCombo;
|
|
||||||
|
|
||||||
public SparkleDialog (string Url) : base ("")
|
|
||||||
{
|
|
||||||
BorderWidth = 12;
|
|
||||||
IconName = "folder-sparkleshare";
|
|
||||||
WidthRequest = 320;
|
|
||||||
Title = "SparkleShare";
|
|
||||||
|
|
||||||
SetPosition (WindowPosition.Center);
|
|
||||||
|
|
||||||
VBox VBox = new VBox (false, 0);
|
|
||||||
|
|
||||||
Label RemoteUrlLabel = new Label (_("Address of remote SparkleShare folder:"));
|
|
||||||
RemoteUrlLabel.Xalign = 0;
|
|
||||||
|
|
||||||
ListStore Defaults = new ListStore (typeof (string));
|
|
||||||
|
|
||||||
RemoteUrlCombo = new ComboBoxEntry (Defaults, 0);
|
|
||||||
|
|
||||||
if (Url.Equals (""))
|
|
||||||
RemoteUrlCombo.Entry.Text = "ssh://";
|
|
||||||
else
|
|
||||||
RemoteUrlCombo.Entry.Text = Url;
|
|
||||||
|
|
||||||
RemoteUrlCombo.Entry.Completion = new EntryCompletion ();
|
|
||||||
RemoteUrlCombo.Entry.Completion.Model = Defaults;
|
|
||||||
|
|
||||||
RemoteUrlCombo.Entry.Completion.InlineCompletion = true;
|
|
||||||
RemoteUrlCombo.Entry.Completion.PopupCompletion = true;
|
|
||||||
RemoteUrlCombo.Entry.Completion.TextColumn = 0;
|
|
||||||
RemoteUrlCombo.Entry.Changed += CheckFields;
|
|
||||||
|
|
||||||
// Add some preset addresses
|
|
||||||
Defaults.AppendValues ("ssh://git@github.com/");
|
|
||||||
Defaults.AppendValues ("ssh://git@git.gnome.org/");
|
|
||||||
Defaults.AppendValues ("ssh://git@fedorahosted.org/");
|
|
||||||
Defaults.AppendValues ("ssh://git@gitorious.org/");
|
|
||||||
|
|
||||||
HButtonBox ButtonBox = new HButtonBox ();
|
|
||||||
ButtonBox.Layout = ButtonBoxStyle.End;
|
|
||||||
ButtonBox.Spacing = 6;
|
|
||||||
ButtonBox.BorderWidth = 0;
|
|
||||||
|
|
||||||
AddButton = new Button (_("Add Folder"));
|
|
||||||
AddButton.Clicked += CloneRepo;
|
|
||||||
AddButton.Sensitive = false;
|
|
||||||
|
|
||||||
Button CancelButton = new Button (Stock.Cancel);
|
|
||||||
|
|
||||||
CancelButton.Clicked += delegate {
|
|
||||||
Destroy ();
|
|
||||||
};
|
|
||||||
|
|
||||||
ButtonBox.Add (CancelButton);
|
|
||||||
ButtonBox.Add (AddButton);
|
|
||||||
|
|
||||||
VBox.PackStart (RemoteUrlLabel, false, false, 0);
|
|
||||||
VBox.PackStart (RemoteUrlCombo, false, false, 12);
|
|
||||||
VBox.PackStart (ButtonBox, false, false, 0);
|
|
||||||
|
|
||||||
Add (VBox);
|
|
||||||
|
|
||||||
ShowAll ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clones a remote repo
|
|
||||||
public void CloneRepo (object o, EventArgs args) {
|
|
||||||
|
|
||||||
// SparkleUI.NotificationIcon.SetSyncingState ();
|
|
||||||
|
|
||||||
HideAll ();
|
|
||||||
|
|
||||||
string RepoRemoteUrl = RemoteUrlCombo.Entry.Text;
|
|
||||||
|
|
||||||
int SlashPos = RepoRemoteUrl.LastIndexOf ("/");
|
|
||||||
int ColumnPos = RepoRemoteUrl.LastIndexOf (":");
|
|
||||||
|
|
||||||
// Check whether a "/" or ":" is used to separate the
|
|
||||||
// repo name from the domain.
|
|
||||||
string RepoName;
|
|
||||||
if (SlashPos > ColumnPos)
|
|
||||||
RepoName = RepoRemoteUrl.Substring (SlashPos + 1);
|
|
||||||
else
|
|
||||||
RepoName = RepoRemoteUrl.Substring (ColumnPos + 1);
|
|
||||||
|
|
||||||
SparkleBubble SyncingBubble;
|
|
||||||
SyncingBubble = new SparkleBubble (String.Format(_("Syncing folder ‘{0}’"), RepoName),
|
|
||||||
_("SparkleShare will notify you when this is done."));
|
|
||||||
|
|
||||||
SyncingBubble.AddAction ("", _("Dismiss"),
|
|
||||||
delegate {
|
|
||||||
SyncingBubble.Close ();
|
|
||||||
});
|
|
||||||
|
|
||||||
SyncingBubble.Show ();
|
|
||||||
|
|
||||||
Process Process = new Process ();
|
|
||||||
Process.EnableRaisingEvents = true;
|
|
||||||
Process.StartInfo.RedirectStandardOutput = true;
|
|
||||||
Process.StartInfo.UseShellExecute = false;
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Config", "[" + RepoName + "] Cloning repository...");
|
|
||||||
|
|
||||||
// Clone into the system's temporary folder
|
|
||||||
Process.StartInfo.FileName = "git";
|
|
||||||
Process.StartInfo.WorkingDirectory = SparklePaths.SparkleTmpPath;
|
|
||||||
Process.StartInfo.Arguments = String.Format ("clone {0} {1}",
|
|
||||||
RepoRemoteUrl,
|
|
||||||
RepoName);
|
|
||||||
|
|
||||||
Process.Start ();
|
|
||||||
Process.WaitForExit ();
|
|
||||||
|
|
||||||
if (Process.ExitCode != 0) {
|
|
||||||
|
|
||||||
SparkleBubble ErrorBubble;
|
|
||||||
ErrorBubble = new SparkleBubble (String.Format(_("Something went wrong while syncing ‘{0}’"), RepoName),
|
|
||||||
"Please double check the address and\n" +
|
|
||||||
"network connection.");
|
|
||||||
|
|
||||||
Directory.Delete (SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, RepoName));
|
|
||||||
|
|
||||||
ErrorBubble.AddAction ("", _("Try Again…"),
|
|
||||||
delegate {
|
|
||||||
SparkleDialog SparkleDialog = new SparkleDialog (RepoRemoteUrl);
|
|
||||||
SparkleDialog.ShowAll ();
|
|
||||||
});
|
|
||||||
ErrorBubble.Show ();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + RepoName + "] Repository cloned");
|
|
||||||
SparkleShare.SparkleUI.UpdateRepositories ();
|
|
||||||
|
|
||||||
Directory.Move (SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, RepoName),
|
|
||||||
SparkleHelpers.CombineMore (SparklePaths.SparklePath, RepoName));
|
|
||||||
|
|
||||||
// Show a confirmation notification
|
|
||||||
SparkleBubble FinishedBubble;
|
|
||||||
FinishedBubble = new SparkleBubble (String.Format(_("Successfully synced folder ‘{0}’"), RepoName),
|
|
||||||
_("Now make great stuff happen!"));
|
|
||||||
|
|
||||||
FinishedBubble.AddAction ("", _("Open Folder"),
|
|
||||||
delegate {
|
|
||||||
Process.StartInfo.FileName = "xdg-open";
|
|
||||||
Process.StartInfo.Arguments = SparkleHelpers.CombineMore (SparklePaths.SparklePath, RepoName);
|
|
||||||
Process.Start ();
|
|
||||||
} );
|
|
||||||
FinishedBubble.Show ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enables the Add button when the fields are
|
|
||||||
// filled in correctly
|
|
||||||
public void CheckFields (object o, EventArgs args) {
|
|
||||||
if (SparkleHelpers.IsGitUrl (RemoteUrlCombo.Entry.Text))
|
|
||||||
AddButton.Sensitive = true;
|
|
||||||
else
|
|
||||||
AddButton.Sensitive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,130 +0,0 @@
|
||||||
// SparkleShare, an instant update workflow to Git.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// 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 Gtk;
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Net;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
public static class SparkleHelpers
|
|
||||||
{
|
|
||||||
|
|
||||||
// Get's the avatar for a specific email address and size
|
|
||||||
public static Gdk.Pixbuf GetAvatar (string Email, int Size)
|
|
||||||
{
|
|
||||||
|
|
||||||
string AvatarPath = CombineMore (SparklePaths.SparkleAvatarPath, Size + "x" + Size);
|
|
||||||
|
|
||||||
if (!Directory.Exists (AvatarPath)) {
|
|
||||||
Directory.CreateDirectory (AvatarPath);
|
|
||||||
SparkleHelpers.DebugInfo ("Config", "Created '" + AvatarPath + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
string AvatarFilePath = CombineMore (AvatarPath, Email);
|
|
||||||
|
|
||||||
if (File.Exists (AvatarFilePath))
|
|
||||||
return new Gdk.Pixbuf (AvatarFilePath);
|
|
||||||
else {
|
|
||||||
|
|
||||||
// Let's try to get the person's gravatar for next time
|
|
||||||
WebClient WebClient = new WebClient ();
|
|
||||||
Uri GravatarUri = new Uri ("http://www.gravatar.com/avatar/" + GetMD5 (Email) +
|
|
||||||
".jpg?s=" + Size + "&d=404");
|
|
||||||
|
|
||||||
string TmpFile = CombineMore (SparklePaths.SparkleTmpPath, Email + Size);
|
|
||||||
|
|
||||||
if (!File.Exists (TmpFile)) {
|
|
||||||
|
|
||||||
WebClient.DownloadFileAsync (GravatarUri, TmpFile);
|
|
||||||
WebClient.DownloadFileCompleted += delegate {
|
|
||||||
File.Delete (AvatarFilePath);
|
|
||||||
FileInfo TmpFileInfo = new FileInfo (TmpFile);
|
|
||||||
if (TmpFileInfo.Length > 255)
|
|
||||||
File.Move (TmpFile, AvatarFilePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall back to a generic icon if there is no gravatar
|
|
||||||
if (File.Exists (AvatarFilePath))
|
|
||||||
return new Gdk.Pixbuf (AvatarFilePath);
|
|
||||||
else
|
|
||||||
return GetIcon ("avatar-default", Size);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Creates an MD5 hash of input
|
|
||||||
public static string GetMD5 (string s)
|
|
||||||
{
|
|
||||||
MD5 md5 = new MD5CryptoServiceProvider ();
|
|
||||||
Byte[] Bytes = ASCIIEncoding.Default.GetBytes (s);
|
|
||||||
Byte[] EncodedBytes = md5.ComputeHash (Bytes);
|
|
||||||
return BitConverter.ToString (EncodedBytes).ToLower ().Replace ("-", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Makes it possible to combine more than
|
|
||||||
// two paths at once.
|
|
||||||
public static string CombineMore (params string [] Parts)
|
|
||||||
{
|
|
||||||
string NewPath = " ";
|
|
||||||
foreach (string Part in Parts)
|
|
||||||
NewPath = Path.Combine (NewPath, Part);
|
|
||||||
return NewPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static IconTheme SparkleTheme = new IconTheme ();
|
|
||||||
|
|
||||||
// Looks up an icon from the system's theme
|
|
||||||
public static Gdk.Pixbuf GetIcon (string Name, int Size)
|
|
||||||
{
|
|
||||||
SparkleTheme.AppendSearchPath (CombineMore (SparklePaths.SparkleInstallPath, "icons"));
|
|
||||||
return SparkleTheme.LoadIcon (Name, Size, IconLookupFlags.GenericFallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Checks if a url is a valid git url
|
|
||||||
public static bool IsGitUrl (string Url)
|
|
||||||
{
|
|
||||||
return Regex.Match (Url, @"(.)+(/|:)(.)+").Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static bool ShowDebugInfo = true;
|
|
||||||
|
|
||||||
// Show debug info if needed
|
|
||||||
public static void DebugInfo (string Type, string Message)
|
|
||||||
{
|
|
||||||
if (ShowDebugInfo) {
|
|
||||||
DateTime DateTime = new DateTime ();
|
|
||||||
string TimeStamp = DateTime.Now.ToString ("HH:mm:ss");
|
|
||||||
Console.WriteLine ("[" + TimeStamp + "]" + "[" + Type + "]" + Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
// SparkleShare, an instant update workflow to Git.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// 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 Mono.Unix;
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
public static class SparklePaths
|
|
||||||
{
|
|
||||||
|
|
||||||
private static UnixUserInfo UnixUserInfo = new UnixUserInfo (UnixEnvironment.UserName);
|
|
||||||
|
|
||||||
public static string HomePath = UnixUserInfo.HomeDirectory;
|
|
||||||
|
|
||||||
public static string SparklePath = Path.Combine (HomePath ,"SparkleShare");
|
|
||||||
|
|
||||||
public static string SparkleTmpPath = Path.Combine (SparklePath, ".tmp");
|
|
||||||
|
|
||||||
public static string SparkleConfigPath = SparkleHelpers.CombineMore (HomePath, ".config", "sparkleshare");
|
|
||||||
|
|
||||||
public static string SparkleInstallPath = SparkleHelpers.CombineMore ("usr", "share",
|
|
||||||
"sparkleshare", "icons", "hicolor");
|
|
||||||
|
|
||||||
public static string SparkleAvatarPath {
|
|
||||||
|
|
||||||
get {
|
|
||||||
|
|
||||||
string XDG_CACHE_HOME = Environment.GetEnvironmentVariable ("XDG_CACHE_HOME");
|
|
||||||
|
|
||||||
if (XDG_CACHE_HOME != null)
|
|
||||||
return Path.Combine (XDG_CACHE_HOME, "sparkleshare");
|
|
||||||
else
|
|
||||||
return SparkleHelpers.CombineMore (HomePath, ".cache", "sparkleshare");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string SparkleIconPath = SparkleHelpers.CombineMore ("usr", "share", "icons", "hicolor");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,478 +0,0 @@
|
||||||
// SparkleShare, an instant update workflow to Git.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// 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 Gtk;
|
|
||||||
using Mono.Unix;
|
|
||||||
using SparkleShare;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Timers;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
// SparkleRepo class holds repository information and timers
|
|
||||||
public class SparkleRepo
|
|
||||||
{
|
|
||||||
|
|
||||||
private Process Process;
|
|
||||||
private Timer FetchTimer;
|
|
||||||
private Timer BufferTimer;
|
|
||||||
private FileSystemWatcher Watcher;
|
|
||||||
|
|
||||||
public string Name;
|
|
||||||
public string Domain;
|
|
||||||
public string LocalPath;
|
|
||||||
public string RemoteOriginUrl;
|
|
||||||
public string CurrentHash;
|
|
||||||
|
|
||||||
public string UserEmail;
|
|
||||||
public string UserName;
|
|
||||||
|
|
||||||
public static string _ (string s)
|
|
||||||
{
|
|
||||||
return Catalog.GetString (s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SparkleRepo (string RepoPath)
|
|
||||||
{
|
|
||||||
|
|
||||||
Process = new Process ();
|
|
||||||
Process.EnableRaisingEvents = true;
|
|
||||||
Process.StartInfo.RedirectStandardOutput = true;
|
|
||||||
Process.StartInfo.UseShellExecute = false;
|
|
||||||
|
|
||||||
// Get the repository's path, example: "/home/user/SparkleShare/repo"
|
|
||||||
LocalPath = RepoPath;
|
|
||||||
Process.StartInfo.WorkingDirectory = LocalPath;
|
|
||||||
|
|
||||||
// Get user.name, example: "User Name"
|
|
||||||
UnixUserInfo UnixUserInfo = new UnixUserInfo (UnixEnvironment.UserName);
|
|
||||||
if (UnixUserInfo.RealName.Equals (""))
|
|
||||||
UserName = "Anonymous";
|
|
||||||
else
|
|
||||||
UserName = UnixUserInfo.RealName;
|
|
||||||
|
|
||||||
Process.StartInfo.FileName = "git";
|
|
||||||
Process.StartInfo.Arguments = "config user.name " + UserName;
|
|
||||||
Process.Start ();
|
|
||||||
|
|
||||||
// Get user.email, example: "user@github.com"
|
|
||||||
UserEmail = "not.set@git-scm.com";
|
|
||||||
Process.StartInfo.FileName = "git";
|
|
||||||
Process.StartInfo.Arguments = "config --get user.email";
|
|
||||||
Process.Start ();
|
|
||||||
UserEmail = Process.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
|
|
||||||
// Get remote.origin.url, example: "ssh://git@github.com/user/repo"
|
|
||||||
Process.StartInfo.FileName = "git";
|
|
||||||
Process.StartInfo.Arguments = "config --get remote.origin.url";
|
|
||||||
Process.Start ();
|
|
||||||
RemoteOriginUrl = Process.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
|
|
||||||
// Get the repository name, example: "Project"
|
|
||||||
Name = Path.GetFileName (LocalPath);
|
|
||||||
|
|
||||||
// Get the domain, example: "github.com"
|
|
||||||
Domain = RemoteOriginUrl;
|
|
||||||
Domain = Domain.Substring (Domain.IndexOf ("@") + 1);
|
|
||||||
if (Domain.IndexOf (":") > -1)
|
|
||||||
Domain = Domain.Substring (0, Domain.IndexOf (":"));
|
|
||||||
else
|
|
||||||
Domain = Domain.Substring (0, Domain.IndexOf ("/"));
|
|
||||||
|
|
||||||
// Get hash of the current commit
|
|
||||||
Process.StartInfo.FileName = "git";
|
|
||||||
Process.StartInfo.Arguments = "rev-list --max-count=1 HEAD";
|
|
||||||
Process.Start ();
|
|
||||||
CurrentHash = Process.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
|
|
||||||
// Watch the repository's folder
|
|
||||||
Watcher = new FileSystemWatcher (LocalPath);
|
|
||||||
Watcher.IncludeSubdirectories = true;
|
|
||||||
Watcher.EnableRaisingEvents = true;
|
|
||||||
Watcher.Filter = "*";
|
|
||||||
Watcher.Changed += new FileSystemEventHandler (OnFileActivity);
|
|
||||||
Watcher.Created += new FileSystemEventHandler (OnFileActivity);
|
|
||||||
Watcher.Deleted += new FileSystemEventHandler (OnFileActivity);
|
|
||||||
|
|
||||||
// Fetch remote changes every 20 seconds
|
|
||||||
FetchTimer = new Timer ();
|
|
||||||
FetchTimer.Interval = 20000;
|
|
||||||
FetchTimer.Elapsed += delegate {
|
|
||||||
Fetch ();
|
|
||||||
};
|
|
||||||
|
|
||||||
FetchTimer.Start ();
|
|
||||||
BufferTimer = new Timer ();
|
|
||||||
|
|
||||||
BufferTimer.Elapsed += delegate (object o, ElapsedEventArgs args) {
|
|
||||||
SparkleHelpers.DebugInfo ("Buffer", "[" + Name + "] Done waiting.");
|
|
||||||
Add ();
|
|
||||||
string Message = FormatCommitMessage ();
|
|
||||||
if (!Message.Equals ("")) {
|
|
||||||
Commit (Message);
|
|
||||||
Fetch ();
|
|
||||||
Push ();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add everything that changed
|
|
||||||
// since SparkleShare was stopped
|
|
||||||
Add ();
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Nothing going on...");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Starts a time buffer when something changes
|
|
||||||
public void OnFileActivity (object o, FileSystemEventArgs args)
|
|
||||||
{
|
|
||||||
WatcherChangeTypes wct = args.ChangeType;
|
|
||||||
if (!ShouldIgnore (args.Name)) {
|
|
||||||
SparkleHelpers.DebugInfo ("Event", "[" + Name + "] " + wct.ToString () + " '" + args.Name + "'");
|
|
||||||
StartBufferTimer ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A buffer that will fetch changes after
|
|
||||||
// file activity has settles down
|
|
||||||
public void StartBufferTimer ()
|
|
||||||
{
|
|
||||||
|
|
||||||
FetchTimer.Stop ();
|
|
||||||
int Interval = 4000;
|
|
||||||
if (!BufferTimer.Enabled) {
|
|
||||||
|
|
||||||
// Delay for a few seconds to see if more files change
|
|
||||||
BufferTimer.Interval = Interval;
|
|
||||||
BufferTimer.Elapsed += delegate (object o, ElapsedEventArgs args) {
|
|
||||||
SparkleHelpers.DebugInfo ("Buffer", "[" + Name + "] Done waiting.");
|
|
||||||
Add ();
|
|
||||||
};
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Buffer", "[" + Name + "] " + "Waiting for more changes...");
|
|
||||||
BufferTimer.Start ();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Extend the delay when something changes
|
|
||||||
BufferTimer.Close ();
|
|
||||||
BufferTimer = new Timer ();
|
|
||||||
BufferTimer.Interval = Interval;
|
|
||||||
|
|
||||||
FetchTimer.Start ();
|
|
||||||
|
|
||||||
BufferTimer.Start ();
|
|
||||||
SparkleHelpers.DebugInfo ("Buffer", "[" + Name + "] " + "Waiting for more changes...");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clones a remote repo
|
|
||||||
public void Clone ()
|
|
||||||
{
|
|
||||||
Process.StartInfo.Arguments = "clone " + RemoteOriginUrl;
|
|
||||||
Process.Start ();
|
|
||||||
|
|
||||||
// Add a gitignore file
|
|
||||||
TextWriter Writer = new StreamWriter (LocalPath + ".gitignore");
|
|
||||||
Writer.WriteLine ("*~"); // Ignore gedit swap files
|
|
||||||
Writer.WriteLine (".*.sw?"); // Ignore vi swap files
|
|
||||||
Writer.Close ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stages the made changes
|
|
||||||
public void Add ()
|
|
||||||
{
|
|
||||||
BufferTimer.Stop ();
|
|
||||||
FetchTimer.Stop ();
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Staging changes...");
|
|
||||||
Process.StartInfo.Arguments = "add --all";
|
|
||||||
Process.Start ();
|
|
||||||
Process.WaitForExit ();
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes staged.");
|
|
||||||
// SparkleUI.NotificationIcon.SetSyncingState ();
|
|
||||||
// SparkleUI.NotificationIcon.SetIdleState ();
|
|
||||||
FetchTimer.Start ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commits the made changes
|
|
||||||
public void Commit (string Message)
|
|
||||||
{
|
|
||||||
SparkleHelpers.DebugInfo ("Commit", "[" + Name + "] " + Message);
|
|
||||||
Process.StartInfo.Arguments = "commit -m \"" + Message + "\"";
|
|
||||||
Process.Start ();
|
|
||||||
Process.WaitForExit ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetches changes from the remote repo
|
|
||||||
public void Fetch ()
|
|
||||||
{
|
|
||||||
FetchTimer.Stop ();
|
|
||||||
// SparkleUI.NotificationIcon.SetSyncingState ();
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Fetching changes...");
|
|
||||||
Process.StartInfo.Arguments = "fetch -v";
|
|
||||||
Process.Start ();
|
|
||||||
string Output = Process.StandardOutput.ReadToEnd ().Trim (); // TODO: This doesn't work :(
|
|
||||||
Process.WaitForExit ();
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes fetched.");
|
|
||||||
if (!Output.Contains ("up to date"))
|
|
||||||
Rebase ();
|
|
||||||
// SparkleUI.NotificationIcon.SetIdleState ();
|
|
||||||
FetchTimer.Start ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merges the fetched changes
|
|
||||||
public void Rebase ()
|
|
||||||
{
|
|
||||||
|
|
||||||
Watcher.EnableRaisingEvents = false;
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Rebasing changes...");
|
|
||||||
Process.StartInfo.Arguments = "rebase origin";
|
|
||||||
Process.WaitForExit ();
|
|
||||||
Process.Start ();
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes rebased.");
|
|
||||||
string Output = Process.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
|
|
||||||
// Show notification if there are updates
|
|
||||||
if (!Output.Contains ("up to date")) {
|
|
||||||
|
|
||||||
if (Output.Contains ("Failed to merge")) {
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Resolving conflict...");
|
|
||||||
|
|
||||||
Process.StartInfo.Arguments = "status";
|
|
||||||
Process.WaitForExit ();
|
|
||||||
Process.Start ();
|
|
||||||
Output = Process.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
|
|
||||||
foreach (string Line in Regex.Split (Output, "\n")) {
|
|
||||||
|
|
||||||
if (Line.Contains ("needs merge")) {
|
|
||||||
|
|
||||||
string ProblemFileName = Line.Substring (Line.IndexOf (": needs merge"));
|
|
||||||
|
|
||||||
Process.StartInfo.Arguments = "checkout --ours " + ProblemFileName;
|
|
||||||
Process.WaitForExit ();
|
|
||||||
Process.Start ();
|
|
||||||
|
|
||||||
DateTime DateTime = new DateTime ();
|
|
||||||
string TimeStamp = DateTime.Now.ToString ("H:mm, d MMM yyyy");
|
|
||||||
|
|
||||||
File.Move (ProblemFileName,
|
|
||||||
ProblemFileName + " (" + UserName + " - " + TimeStamp + ")");
|
|
||||||
|
|
||||||
Process.StartInfo.Arguments
|
|
||||||
= "checkout --theirs " + ProblemFileName;
|
|
||||||
Process.WaitForExit ();
|
|
||||||
Process.Start ();
|
|
||||||
|
|
||||||
string ConflictTitle = "A mid-air collision happened!\n";
|
|
||||||
string ConflictSubtext = "Don't worry, SparkleShare made\na copy of the conflicting files.";
|
|
||||||
|
|
||||||
SparkleBubble ConflictBubble =
|
|
||||||
new SparkleBubble(_(ConflictTitle), _(ConflictSubtext));
|
|
||||||
|
|
||||||
ConflictBubble.Show ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Add ();
|
|
||||||
|
|
||||||
Process.StartInfo.Arguments = "rebase --continue";
|
|
||||||
Process.WaitForExit ();
|
|
||||||
Process.Start ();
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Conflict resolved.");
|
|
||||||
Push ();
|
|
||||||
Fetch ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the last committer e-mail
|
|
||||||
Process.StartInfo.Arguments = "log --format=\"%ae\" -1";
|
|
||||||
Process.Start ();
|
|
||||||
string LastCommitEmail = Process.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
|
|
||||||
// Get the last commit message
|
|
||||||
Process.StartInfo.Arguments = "log --format=\"%s\" -1";
|
|
||||||
Process.Start ();
|
|
||||||
string LastCommitMessage = Process.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
|
|
||||||
// Get the last commiter
|
|
||||||
Process.StartInfo.Arguments = "log --format=\"%an\" -1";
|
|
||||||
Process.Start ();
|
|
||||||
string LastCommitUserName = Process.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
|
|
||||||
string NotifySettingFile = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath,
|
|
||||||
"sparkleshare.notify");
|
|
||||||
|
|
||||||
if (File.Exists (NotifySettingFile)) {
|
|
||||||
|
|
||||||
SparkleHelpers.DebugInfo ("Notification", "[" + Name + "] Showing message...");
|
|
||||||
|
|
||||||
SparkleBubble StuffChangedBubble = new SparkleBubble (LastCommitUserName, LastCommitMessage);
|
|
||||||
StuffChangedBubble.Icon = SparkleHelpers.GetAvatar (LastCommitEmail, 48);
|
|
||||||
|
|
||||||
// Add a button to open the folder where the changed file is
|
|
||||||
StuffChangedBubble.AddAction ("", _("Open Folder"),
|
|
||||||
delegate {
|
|
||||||
switch (SparklePlatform.Name) {
|
|
||||||
case "GNOME":
|
|
||||||
Process.StartInfo.FileName = "xdg-open";
|
|
||||||
break;
|
|
||||||
case "OSX":
|
|
||||||
Process.StartInfo.FileName = "open";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Process.StartInfo.Arguments = LocalPath;
|
|
||||||
Process.Start ();
|
|
||||||
Process.StartInfo.FileName = "git";
|
|
||||||
} );
|
|
||||||
|
|
||||||
StuffChangedBubble.Show ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Watcher.EnableRaisingEvents = true;
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Nothing going on...");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pushes the changes to the remote repo
|
|
||||||
public void Push ()
|
|
||||||
{
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Pushing changes...");
|
|
||||||
Process.StartInfo.Arguments = "push";
|
|
||||||
Process.Start ();
|
|
||||||
Process.WaitForExit ();
|
|
||||||
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Changes pushed.");
|
|
||||||
// SparkleUI.NotificationIcon.SetIdleState ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignores Repos, dotfiles, swap files and the like.
|
|
||||||
public bool ShouldIgnore (string FileName) {
|
|
||||||
if (FileName.Substring (0, 1).Equals (".") ||
|
|
||||||
FileName.Contains (".lock") ||
|
|
||||||
FileName.Contains (".git") ||
|
|
||||||
FileName.Contains ("/.") ||
|
|
||||||
Directory.Exists (LocalPath + FileName))
|
|
||||||
return true; // Yes, ignore it.
|
|
||||||
else if (FileName.Length > 3 && FileName.Substring (FileName.Length - 4).Equals (".swp"))
|
|
||||||
return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a pretty commit message based on what has changed
|
|
||||||
public string FormatCommitMessage ()
|
|
||||||
{
|
|
||||||
|
|
||||||
bool DoneAddCommit = false;
|
|
||||||
bool DoneEditCommit = false;
|
|
||||||
bool DoneRenameCommit = false;
|
|
||||||
bool DoneDeleteCommit = false;
|
|
||||||
int FilesAdded = 0;
|
|
||||||
int FilesEdited = 0;
|
|
||||||
int FilesRenamed = 0;
|
|
||||||
int FilesDeleted = 0;
|
|
||||||
|
|
||||||
Process.StartInfo.Arguments = "status";
|
|
||||||
Process.Start ();
|
|
||||||
string Output = Process.StandardOutput.ReadToEnd ();
|
|
||||||
|
|
||||||
foreach (string Line in Regex.Split (Output, "\n")) {
|
|
||||||
if (Line.IndexOf ("new file:") > -1)
|
|
||||||
FilesAdded++;
|
|
||||||
if (Line.IndexOf ("modified:") > -1)
|
|
||||||
FilesEdited++;
|
|
||||||
if (Line.IndexOf ("renamed:") > -1)
|
|
||||||
FilesRenamed++;
|
|
||||||
if (Line.IndexOf ("deleted:") > -1)
|
|
||||||
FilesDeleted++;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string Line in Regex.Split (Output, "\n")) {
|
|
||||||
|
|
||||||
// Format message for when files are added,
|
|
||||||
// example: "added 'file' and 3 more."
|
|
||||||
if (Line.IndexOf ("new file:") > -1 && !DoneAddCommit) {
|
|
||||||
DoneAddCommit = true;
|
|
||||||
if (FilesAdded > 1)
|
|
||||||
return "added ‘" +
|
|
||||||
Line.Replace ("#\tnew file:", "").Trim () +
|
|
||||||
"’ and " + (FilesAdded - 1) + " more.";
|
|
||||||
else
|
|
||||||
return "added ‘" +
|
|
||||||
Line.Replace ("#\tnew file:", "").Trim () + "’.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format message for when files are edited,
|
|
||||||
// example: "edited 'file'."
|
|
||||||
if (Line.IndexOf ("modified:") > -1 && !DoneEditCommit) {
|
|
||||||
DoneEditCommit = true;
|
|
||||||
if (FilesEdited > 1)
|
|
||||||
return "edited ‘" +
|
|
||||||
Line.Replace ("#\tmodified:", "").Trim () +
|
|
||||||
"’ and " + (FilesEdited - 1) + " more.";
|
|
||||||
else
|
|
||||||
return "edited ‘" +
|
|
||||||
Line.Replace ("#\tmodified:", "").Trim () + "’.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format message for when files are edited,
|
|
||||||
// example: "deleted 'file'."
|
|
||||||
if (Line.IndexOf ("deleted:") > -1 && !DoneDeleteCommit) {
|
|
||||||
DoneDeleteCommit = true;
|
|
||||||
if (FilesDeleted > 1)
|
|
||||||
return "deleted ‘" +
|
|
||||||
Line.Replace ("#\tdeleted:", "").Trim () +
|
|
||||||
"’ and " + (FilesDeleted - 1) + " more.";
|
|
||||||
else
|
|
||||||
return "deleted ‘" +
|
|
||||||
Line.Replace ("#\tdeleted:", "").Trim () + "’.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format message for when files are renamed,
|
|
||||||
// example: "renamed 'file' to 'new name'."
|
|
||||||
if (Line.IndexOf ("renamed:") > -1 && !DoneRenameCommit) {
|
|
||||||
DoneDeleteCommit = true;
|
|
||||||
if (FilesRenamed > 1)
|
|
||||||
return "renamed ‘" +
|
|
||||||
Line.Replace ("#\trenamed:", "").Trim ().Replace
|
|
||||||
(" -> ", "’ to ‘") + "’ and " + (FilesDeleted - 1) +
|
|
||||||
" more.";
|
|
||||||
else
|
|
||||||
return "renamed ‘" +
|
|
||||||
Line.Replace ("#\trenamed:", "").Trim ().Replace
|
|
||||||
(" -> ", "’ to ‘") + "’.";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nothing happened:
|
|
||||||
return "";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
// SparkleShare, an instant update workflow to Git.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// 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 Gtk;
|
|
||||||
using Mono.Unix;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
// This is SparkleShare!
|
|
||||||
public class SparkleShare {
|
|
||||||
|
|
||||||
// Short alias for the translations
|
|
||||||
public static string _ (string s) {
|
|
||||||
return Catalog.GetString (s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SparkleRepo [] Repositories;
|
|
||||||
public static SparkleUI SparkleUI;
|
|
||||||
|
|
||||||
public static void Main (string [] args) {
|
|
||||||
|
|
||||||
// Use translations
|
|
||||||
Catalog.Init ("i18n", "locale");
|
|
||||||
|
|
||||||
// Check if git is installed
|
|
||||||
Process Process = new Process ();
|
|
||||||
Process.StartInfo.FileName = "git";
|
|
||||||
Process.StartInfo.RedirectStandardOutput = true;
|
|
||||||
Process.StartInfo.UseShellExecute = false;
|
|
||||||
Process.Start ();
|
|
||||||
|
|
||||||
if (Process.StandardOutput.ReadToEnd ().IndexOf ("version") == -1) {
|
|
||||||
Console.WriteLine (_("Git wasn't found."));
|
|
||||||
Console.WriteLine (_("You can get Git from http://git-scm.com/."));
|
|
||||||
Environment.Exit (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't allow running as root
|
|
||||||
UnixUserInfo UnixUserInfo = new UnixUserInfo (UnixEnvironment.UserName);
|
|
||||||
if (UnixUserInfo.UserId == 0) {
|
|
||||||
Console.WriteLine (_("Sorry, you can't run SparkleShare with these permissions."));
|
|
||||||
Console.WriteLine (_("Things will go utterly wrong."));
|
|
||||||
Environment.Exit (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the command line arguments
|
|
||||||
bool HideUI = false;
|
|
||||||
if (args.Length > 0) {
|
|
||||||
foreach (string Argument in args) {
|
|
||||||
if (Argument.Equals ("--disable-gui") || Argument.Equals ("-d"))
|
|
||||||
HideUI = true;
|
|
||||||
if (Argument.Equals ("--help") || Argument.Equals ("-h")) {
|
|
||||||
ShowHelp ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Gtk.Application.Init ();
|
|
||||||
|
|
||||||
SparkleUI = new SparkleUI (HideUI);
|
|
||||||
|
|
||||||
// The main loop
|
|
||||||
Gtk.Application.Run ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prints the help output
|
|
||||||
public static void ShowHelp () {
|
|
||||||
Console.WriteLine (_("SparkleShare Copyright (C) 2010 Hylke Bons"));
|
|
||||||
Console.WriteLine (" ");
|
|
||||||
Console.WriteLine (_("This program comes with ABSOLUTELY NO WARRANTY."));
|
|
||||||
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 syncs the ~/SparkleShare folder with remote repositories."));
|
|
||||||
Console.WriteLine (" ");
|
|
||||||
Console.WriteLine (_("Usage: sparkleshare [start|stop|restart] [OPTION]..."));
|
|
||||||
Console.WriteLine (_("Sync SparkleShare folder with remote repositories."));
|
|
||||||
Console.WriteLine (" ");
|
|
||||||
Console.WriteLine (_("Arguments:"));
|
|
||||||
Console.WriteLine (_("\t -d, --disable-gui\tDon't show the notification icon."));
|
|
||||||
Console.WriteLine (_("\t -h, --help\t\tDisplay this help text."));
|
|
||||||
Console.WriteLine (" ");
|
|
||||||
Environment.Exit (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProductVersion>8.0.50727</ProductVersion>
|
|
||||||
<ProjectGuid>{728483AA-E34B-4441-BF2C-C8BC2901E4E0}</ProjectGuid>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<AssemblyName>SparkleShare</AssemblyName>
|
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
|
||||||
<RootNamespace>SparkleShare</RootNamespace>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug</OutputPath>
|
|
||||||
<DefineConstants>DEBUG</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>none</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Release</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
|
|
||||||
<Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
|
|
||||||
<Reference Include="pango-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="Mono.Posix" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="SparkleBubble.cs" />
|
|
||||||
<Compile Include="SparkleDialog.cs" />
|
|
||||||
<Compile Include="SparkleHelpers.cs" />
|
|
||||||
<Compile Include="SparklePaths.cs" />
|
|
||||||
<Compile Include="SparklePlatform.cs" />
|
|
||||||
<Compile Include="SparkleRepo.cs" />
|
|
||||||
<Compile Include="SparkleShare.cs" />
|
|
||||||
<Compile Include="SparkleSpinner.cs" />
|
|
||||||
<Compile Include="SparkleStatusIcon.cs" />
|
|
||||||
<Compile Include="SparkleUI.cs" />
|
|
||||||
<Compile Include="SparkleWindow.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\notify-sharp\notify-sharp.csproj">
|
|
||||||
<Project>{005CCA8E-DFBF-464A-B6DA-452C62D4589C}</Project>
|
|
||||||
<Name>notify-sharp</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
|
@ -1,236 +0,0 @@
|
||||||
// SparkleShare, an instant update workflow to Git.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// 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 Gtk;
|
|
||||||
using Mono.Unix;
|
|
||||||
using SparkleShare;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Timers;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
public class SparkleStatusIcon : StatusIcon {
|
|
||||||
|
|
||||||
private Timer Timer;
|
|
||||||
private int SyncingState;
|
|
||||||
|
|
||||||
// Short alias for the translations
|
|
||||||
public static string _ (string s) {
|
|
||||||
return Catalog.GetString (s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public EventHandler CreateWindowDelegate (SparkleRepo SparkleRepo) {
|
|
||||||
return delegate {
|
|
||||||
SparkleWindow SparkleWindow = new SparkleWindow (SparkleRepo);
|
|
||||||
SparkleWindow.ShowAll ();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public SparkleStatusIcon () : base () {
|
|
||||||
|
|
||||||
Timer = new Timer ();
|
|
||||||
Activate += ShowMenu;
|
|
||||||
|
|
||||||
// 0 = Everything up to date
|
|
||||||
// 1 = Syncing in progress
|
|
||||||
// -1 = Error syncing
|
|
||||||
SyncingState = 0;
|
|
||||||
|
|
||||||
SetIdleState ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ShowMenu (object o, EventArgs Args) {
|
|
||||||
|
|
||||||
Menu Menu = new Menu ();
|
|
||||||
|
|
||||||
string StateText = "";
|
|
||||||
switch (SyncingState) {
|
|
||||||
case -1:
|
|
||||||
StateText = _("Error syncing");
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
StateText = _("Everything is up to date");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
StateText = _("Syncing…");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
MenuItem StatusMenuItem = new MenuItem (StateText);
|
|
||||||
StatusMenuItem.Sensitive = false;
|
|
||||||
|
|
||||||
Menu.Add (StatusMenuItem);
|
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
|
||||||
|
|
||||||
Action FolderAction = new Action ("", "SparkleShare");
|
|
||||||
FolderAction.IconName = "folder-sparkleshare";
|
|
||||||
FolderAction.IsImportant = true;
|
|
||||||
FolderAction.Activated += delegate {
|
|
||||||
Process Process = new Process ();
|
|
||||||
switch (SparklePlatform.Name) {
|
|
||||||
case "GNOME":
|
|
||||||
Process.StartInfo.FileName = "xdg-open";
|
|
||||||
break;
|
|
||||||
case "OSX":
|
|
||||||
Process.StartInfo.FileName = "open";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Process.StartInfo.Arguments = SparklePaths.SparklePath;
|
|
||||||
Process.Start ();
|
|
||||||
};
|
|
||||||
Menu.Add (FolderAction.CreateMenuItem ());
|
|
||||||
|
|
||||||
Action [] FolderItems =
|
|
||||||
new Action [SparkleShare.Repositories.Length];
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (SparkleRepo SparkleRepo in SparkleShare.Repositories) {
|
|
||||||
FolderItems [i] = new Action ("", SparkleRepo.Name);
|
|
||||||
FolderItems [i].IconName = "folder";
|
|
||||||
FolderItems [i].IsImportant = true;
|
|
||||||
FolderItems [i].Activated += CreateWindowDelegate (SparkleRepo);
|
|
||||||
Menu.Add (FolderItems [i].CreateMenuItem ());
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
MenuItem AddItem = new MenuItem (_("Add a Remote Folder…"));
|
|
||||||
AddItem.Activated += delegate {
|
|
||||||
SparkleDialog SparkleDialog = new SparkleDialog ("");
|
|
||||||
SparkleDialog.ShowAll ();
|
|
||||||
};
|
|
||||||
Menu.Add (AddItem);
|
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
|
||||||
|
|
||||||
CheckMenuItem NotifyCheckMenuItem =
|
|
||||||
new CheckMenuItem (_("Show Notifications"));
|
|
||||||
Menu.Add (NotifyCheckMenuItem);
|
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
|
||||||
|
|
||||||
string NotifyChangesFileName =
|
|
||||||
SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath,
|
|
||||||
"sparkleshare.notify");
|
|
||||||
|
|
||||||
if (System.IO.File.Exists (NotifyChangesFileName))
|
|
||||||
NotifyCheckMenuItem.Active = true;
|
|
||||||
|
|
||||||
NotifyCheckMenuItem.Toggled += delegate {
|
|
||||||
if (System.IO.File.Exists (NotifyChangesFileName)) {
|
|
||||||
File.Delete (NotifyChangesFileName);
|
|
||||||
} else {
|
|
||||||
System.IO.File.Create (NotifyChangesFileName);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
MenuItem AboutItem = new MenuItem (_("Visit Website"));
|
|
||||||
AboutItem.Activated += delegate {
|
|
||||||
Process Process = new Process ();
|
|
||||||
switch (SparklePlatform.Name) {
|
|
||||||
case "GNOME":
|
|
||||||
Process.StartInfo.FileName = "xdg-open";
|
|
||||||
break;
|
|
||||||
case "OSX":
|
|
||||||
Process.StartInfo.FileName = "open";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Process.StartInfo.Arguments = "http://www.sparkleshare.org/";
|
|
||||||
Process.Start ();
|
|
||||||
};
|
|
||||||
Menu.Add (AboutItem);
|
|
||||||
|
|
||||||
Menu.Add (new SeparatorMenuItem ());
|
|
||||||
MenuItem QuitItem = new MenuItem (_("Quit"));
|
|
||||||
QuitItem.Activated += Quit;
|
|
||||||
Menu.Add (QuitItem);
|
|
||||||
Menu.ShowAll ();
|
|
||||||
Menu.Popup (null, null, SetPosition, 0, Global.CurrentEventTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetIdleState () {
|
|
||||||
Timer.Stop ();
|
|
||||||
Pixbuf = SparkleHelpers.GetIcon ("folder-sparkleshare", 24);
|
|
||||||
SyncingState = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Changes the status icon to the syncing animation
|
|
||||||
// TODO: There are UI freezes when switching back and forth
|
|
||||||
// bewteen syncing and idle state
|
|
||||||
public void SetSyncingState () {
|
|
||||||
|
|
||||||
SyncingState = 1;
|
|
||||||
|
|
||||||
int CycleDuration = 250;
|
|
||||||
int CurrentStep = 0;
|
|
||||||
int Size = 24;
|
|
||||||
|
|
||||||
Gdk.Pixbuf SpinnerGallery =
|
|
||||||
SparkleHelpers.GetIcon ("process-syncing-sparkleshare", Size);
|
|
||||||
|
|
||||||
int FramesInWidth = SpinnerGallery.Width / Size;
|
|
||||||
int FramesInHeight = SpinnerGallery.Height / Size;
|
|
||||||
int NumSteps = FramesInWidth * FramesInHeight;
|
|
||||||
Gdk.Pixbuf [] Images = new Gdk.Pixbuf [NumSteps - 1];
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (int y = 0; y < FramesInHeight; y++) {
|
|
||||||
for (int x = 0; x < FramesInWidth; x++) {
|
|
||||||
if (!(y == 0 && x == 0)) {
|
|
||||||
Images [i] = new Gdk.Pixbuf (SpinnerGallery,
|
|
||||||
x * Size, y * Size, Size, Size);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer = new Timer ();
|
|
||||||
Timer.Interval = CycleDuration / NumSteps;
|
|
||||||
Timer.Elapsed += delegate {
|
|
||||||
if (CurrentStep < NumSteps)
|
|
||||||
CurrentStep++;
|
|
||||||
else
|
|
||||||
CurrentStep = 0;
|
|
||||||
Pixbuf = Images [CurrentStep];
|
|
||||||
};
|
|
||||||
Timer.Start ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Changes the status icon to the error icon
|
|
||||||
public void SetErrorState () {
|
|
||||||
IconName = "folder-sync-error";
|
|
||||||
SyncingState = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPosition (Menu menu, out int x, out int y,
|
|
||||||
out bool push_in) {
|
|
||||||
|
|
||||||
PositionMenu (menu, out x, out y, out push_in, Handle);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quits the program
|
|
||||||
public void Quit (object o, EventArgs args) {
|
|
||||||
System.IO.File.Delete
|
|
||||||
(SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath +
|
|
||||||
"sparkleshare.pid"));
|
|
||||||
Application.Quit ();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,249 +0,0 @@
|
||||||
// SparkleShare, an instant update workflow to Git.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// 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 Gtk;
|
|
||||||
using Mono.Unix;
|
|
||||||
using SparkleShare;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
public class SparkleUI
|
|
||||||
{
|
|
||||||
|
|
||||||
private Process Process;
|
|
||||||
|
|
||||||
// Short alias for the translations
|
|
||||||
public static string _ (string s)
|
|
||||||
{
|
|
||||||
return Catalog.GetString (s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SparkleStatusIcon NotificationIcon;
|
|
||||||
|
|
||||||
public SparkleUI (bool HideUI)
|
|
||||||
{
|
|
||||||
|
|
||||||
Process = new Process ();
|
|
||||||
Process.EnableRaisingEvents = true;
|
|
||||||
Process.StartInfo.RedirectStandardOutput = true;
|
|
||||||
Process.StartInfo.UseShellExecute = false;
|
|
||||||
|
|
||||||
string SparklePath = SparklePaths.SparklePath;
|
|
||||||
|
|
||||||
|
|
||||||
// Create .desktop entry in autostart folder to
|
|
||||||
// start SparkleShare on each login
|
|
||||||
switch (SparklePlatform.Name) {
|
|
||||||
case "GNOME":
|
|
||||||
|
|
||||||
string autostart_path = SparkleHelpers.CombineMore (SparklePaths.HomePath, ".config", "autostart");
|
|
||||||
string desktopfile_path = SparkleHelpers.CombineMore (autostart_path, "sparkleshare.desktop");
|
|
||||||
|
|
||||||
if (!File.Exists (desktopfile_path)) {
|
|
||||||
if (!Directory.Exists (autostart_path))
|
|
||||||
Directory.CreateDirectory (autostart_path);
|
|
||||||
TextWriter writer = new StreamWriter (desktopfile_path);
|
|
||||||
writer.WriteLine ("[Desktop Entry]\n" +
|
|
||||||
"Name=SparkleShare\n" +
|
|
||||||
"Exec=sparkleshare start\n" +
|
|
||||||
"Icon=folder-sparkleshare\n" +
|
|
||||||
"Terminal=false\n" +
|
|
||||||
"X-GNOME-Autostart-enabled=true");
|
|
||||||
writer.Close ();
|
|
||||||
SparkleHelpers.DebugInfo ("Config", " Created '" + desktopfile_path + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Create 'SparkleShare' folder in the user's home folder
|
|
||||||
// if it's not there already
|
|
||||||
if (!Directory.Exists (SparklePath)) {
|
|
||||||
|
|
||||||
Directory.CreateDirectory (SparklePath);
|
|
||||||
SparkleHelpers.DebugInfo ("Config", " Created '" + SparklePath + "'");
|
|
||||||
|
|
||||||
// Add a special icon to the SparkleShare folder
|
|
||||||
switch (SparklePlatform.Name) {
|
|
||||||
case "GNOME":
|
|
||||||
|
|
||||||
Process.StartInfo.FileName = "gvfs-set-attribute";
|
|
||||||
Process.StartInfo.Arguments = SparklePath + " metadata::custom-icon " +
|
|
||||||
"file:///usr/share/icons/hicolor/48x48/places/" +
|
|
||||||
"folder-sparkleshare.png";
|
|
||||||
Process.Start ();
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the SparkleShare folder to the bookmarks
|
|
||||||
switch (SparklePlatform.Name) {
|
|
||||||
case "GNOME":
|
|
||||||
|
|
||||||
string BookmarksFileName =
|
|
||||||
Path.Combine (SparklePaths.HomePath, ".gtk-bookmarks");
|
|
||||||
|
|
||||||
if (File.Exists (BookmarksFileName)) {
|
|
||||||
TextWriter TextWriter = File.AppendText (BookmarksFileName);
|
|
||||||
TextWriter.WriteLine ("file://" + SparklePath + " SparkleShare");
|
|
||||||
TextWriter.Close ();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a directory to store temporary files in
|
|
||||||
if (!Directory.Exists (SparklePaths.SparkleTmpPath))
|
|
||||||
Directory.CreateDirectory (SparklePaths.SparkleTmpPath);
|
|
||||||
|
|
||||||
if (!HideUI)
|
|
||||||
NotificationIcon = new SparkleStatusIcon ();
|
|
||||||
|
|
||||||
UpdateRepositories ();
|
|
||||||
|
|
||||||
// Don't create the window and status
|
|
||||||
// icon when --disable-gui was given
|
|
||||||
if (!HideUI) {
|
|
||||||
|
|
||||||
// Show a notification if there are no folders yet
|
|
||||||
if (SparkleShare.Repositories.Length == 0) {
|
|
||||||
|
|
||||||
SparkleBubble NoFoldersBubble;
|
|
||||||
NoFoldersBubble = new SparkleBubble (_("Welcome to SparkleShare!"),
|
|
||||||
_("You don't have any folders set up yet."));
|
|
||||||
|
|
||||||
NoFoldersBubble.IconName = "folder-sparkleshare";
|
|
||||||
NoFoldersBubble.AddAction ("", _("Add a Folder…"), delegate {
|
|
||||||
SparkleDialog SparkleDialog = new SparkleDialog ("");
|
|
||||||
SparkleDialog.ShowAll ();
|
|
||||||
/* Process.StartInfo.FileName = "xdg-open";
|
|
||||||
Process.StartInfo.Arguments = SparklePaths.SparklePath;
|
|
||||||
Process.Start ();
|
|
||||||
*/
|
|
||||||
} );
|
|
||||||
|
|
||||||
NoFoldersBubble.Show ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: This crashes
|
|
||||||
/*
|
|
||||||
|
|
||||||
// Watch the SparkleShare folder and pop up the
|
|
||||||
// Add dialog when a new folder is created
|
|
||||||
|
|
||||||
FileSystemWatcher Watcher = new FileSystemWatcher (SparklePaths.SparklePath);
|
|
||||||
Watcher.IncludeSubdirectories = false;
|
|
||||||
Watcher.EnableRaisingEvents = true;
|
|
||||||
Watcher.Created += delegate (object o, FileSystemEventArgs args) {
|
|
||||||
WatcherChangeTypes wct = args.ChangeType;
|
|
||||||
SparkleHelpers.DebugInfo ("Event",
|
|
||||||
wct.ToString () +
|
|
||||||
" '" + args.Name + "'");
|
|
||||||
SparkleDialog SparkleDialog = new SparkleDialog ();
|
|
||||||
SparkleDialog.ShowAll ();
|
|
||||||
};
|
|
||||||
|
|
||||||
// When a repo folder is deleted, don't sync and update the UI
|
|
||||||
Watcher.Deleted += delegate (object o, FileSystemEventArgs args) {
|
|
||||||
WatcherChangeTypes wct = args.ChangeType;
|
|
||||||
SparkleHelpers.DebugInfo ("Event",
|
|
||||||
wct.ToString () +
|
|
||||||
" '" + args.Name + "'");
|
|
||||||
SparkleUI SparkleUI = new SparkleUI ();
|
|
||||||
SparkleUI.ShowAll ();
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Create place to store configuration user's home folder
|
|
||||||
string ConfigPath = SparklePaths.SparkleConfigPath;
|
|
||||||
string AvatarPath = SparklePaths.SparkleAvatarPath;
|
|
||||||
|
|
||||||
if (!Directory.Exists (ConfigPath)) {
|
|
||||||
|
|
||||||
Directory.CreateDirectory (ConfigPath);
|
|
||||||
SparkleHelpers.DebugInfo ("Config", " Created '" + ConfigPath + "'");
|
|
||||||
|
|
||||||
// Create a place to store the avatars
|
|
||||||
Directory.CreateDirectory (AvatarPath);
|
|
||||||
SparkleHelpers.DebugInfo ("Config", " Created '" + AvatarPath + "'");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
string NotifySettingFile = SparkleHelpers.CombineMore (SparklePaths.SparkleConfigPath,
|
|
||||||
"sparkleshare.notify");
|
|
||||||
|
|
||||||
// Enable notifications by default
|
|
||||||
if (!File.Exists (NotifySettingFile))
|
|
||||||
File.Create (NotifySettingFile);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void UpdateRepositories ()
|
|
||||||
{
|
|
||||||
|
|
||||||
string SparklePath = SparklePaths.SparklePath;
|
|
||||||
// Get all the repos in ~/SparkleShare
|
|
||||||
SparkleRepo [] TmpRepos = new SparkleRepo [Directory.GetDirectories (SparklePath).Length];
|
|
||||||
|
|
||||||
int FolderCount = 0;
|
|
||||||
foreach (string Folder in Directory.GetDirectories (SparklePath)) {
|
|
||||||
|
|
||||||
// Check if the folder is a git repo
|
|
||||||
if (Directory.Exists (SparkleHelpers.CombineMore (Folder, ".git"))) {
|
|
||||||
|
|
||||||
TmpRepos [FolderCount] = new SparkleRepo (Folder);
|
|
||||||
FolderCount++;
|
|
||||||
|
|
||||||
// TODO: emblems don't show up in nautilus
|
|
||||||
// Attach emblems
|
|
||||||
switch (SparklePlatform.Name) {
|
|
||||||
case "GNOME":
|
|
||||||
|
|
||||||
Process.StartInfo.FileName = "gvfs-set-attribute";
|
|
||||||
Process.StartInfo.Arguments = "-t string \"" + Folder +
|
|
||||||
"\" metadata::emblems [synced]";
|
|
||||||
Process.Start ();
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SparkleShare.Repositories = new SparkleRepo [FolderCount];
|
|
||||||
Array.Copy (TmpRepos, SparkleShare.Repositories, FolderCount);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,230 +0,0 @@
|
||||||
// SparkleShare, an instant update workflow to Git.
|
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// 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 Gtk;
|
|
||||||
using Mono.Unix;
|
|
||||||
using SparkleShare;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Timers;
|
|
||||||
|
|
||||||
namespace SparkleShare {
|
|
||||||
|
|
||||||
public class SparkleWindow : Window
|
|
||||||
{
|
|
||||||
|
|
||||||
// Short alias for the translations
|
|
||||||
public static string _ (string s)
|
|
||||||
{
|
|
||||||
return Catalog.GetString (s);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SparkleRepo SparkleRepo;
|
|
||||||
private VBox LayoutVertical;
|
|
||||||
private ScrolledWindow LogScrolledWindow;
|
|
||||||
private string SelectedEmail;
|
|
||||||
|
|
||||||
public SparkleWindow (SparkleRepo Repo) : base ("")
|
|
||||||
{
|
|
||||||
|
|
||||||
SparkleRepo = Repo;
|
|
||||||
SelectedEmail = "";
|
|
||||||
SetSizeRequest (640, 480);
|
|
||||||
SetPosition (WindowPosition.Center);
|
|
||||||
BorderWidth = 12;
|
|
||||||
Title = String.Format(_("‘{0}’ on {1}"), SparkleRepo.Name,
|
|
||||||
SparkleRepo.RemoteOriginUrl.TrimEnd (("/" + SparkleRepo.Name + ".git").ToCharArray ()));
|
|
||||||
IconName = "folder";
|
|
||||||
|
|
||||||
LayoutVertical = new VBox (false, 12);
|
|
||||||
|
|
||||||
LayoutVertical.PackStart (CreateEventLog (), true, true, 0);
|
|
||||||
|
|
||||||
HButtonBox DialogButtons = new HButtonBox ();
|
|
||||||
DialogButtons.Layout = ButtonBoxStyle.Edge;
|
|
||||||
DialogButtons.BorderWidth = 0;
|
|
||||||
|
|
||||||
Button OpenFolderButton = new Button (_("Open Folder"));
|
|
||||||
OpenFolderButton.Clicked += delegate (object o, EventArgs args) {
|
|
||||||
Process Process = new Process ();
|
|
||||||
Process.StartInfo.FileName = "xdg-open";
|
|
||||||
Process.StartInfo.Arguments =
|
|
||||||
SparkleHelpers.CombineMore (SparklePaths.SparklePath, SparkleRepo.Name);
|
|
||||||
Process.Start ();
|
|
||||||
Destroy ();
|
|
||||||
};
|
|
||||||
|
|
||||||
Button CloseButton = new Button (Stock.Close);
|
|
||||||
CloseButton.Clicked += delegate (object o, EventArgs args) {
|
|
||||||
Destroy ();
|
|
||||||
};
|
|
||||||
|
|
||||||
DialogButtons.Add (OpenFolderButton);
|
|
||||||
DialogButtons.Add (CloseButton);
|
|
||||||
|
|
||||||
LayoutVertical.PackStart (DialogButtons, false, false, 0);
|
|
||||||
|
|
||||||
Add (LayoutVertical);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void UpdateEventLog ()
|
|
||||||
{
|
|
||||||
|
|
||||||
LayoutVertical.Remove (LogScrolledWindow);
|
|
||||||
LogScrolledWindow = CreateEventLog ();
|
|
||||||
LayoutVertical.PackStart (LogScrolledWindow, true, true, 0);
|
|
||||||
ShowAll ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public ScrolledWindow CreateEventLog ()
|
|
||||||
{
|
|
||||||
|
|
||||||
ListStore LogStore = new ListStore (typeof (Gdk.Pixbuf),
|
|
||||||
typeof (string),
|
|
||||||
typeof (string),
|
|
||||||
typeof (string));
|
|
||||||
|
|
||||||
Process Process = new Process ();
|
|
||||||
Process.EnableRaisingEvents = true;
|
|
||||||
Process.StartInfo.RedirectStandardOutput = true;
|
|
||||||
Process.StartInfo.UseShellExecute = false;
|
|
||||||
Process.StartInfo.FileName = "git";
|
|
||||||
|
|
||||||
string Output = "";
|
|
||||||
|
|
||||||
Process.StartInfo.WorkingDirectory = SparkleRepo.LocalPath;
|
|
||||||
// We're using the snowman here to separate messages :)
|
|
||||||
Process.StartInfo.Arguments = "log --format=\"%at☃%s☃%an☃%cr☃%ae\" -25";
|
|
||||||
Process.Start ();
|
|
||||||
|
|
||||||
Output += "\n" + Process.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
|
|
||||||
Output = Output.TrimStart ("\n".ToCharArray ());
|
|
||||||
string [] Lines = Regex.Split (Output, "\n");
|
|
||||||
|
|
||||||
// Sort by time and get the last 25
|
|
||||||
Array.Sort (Lines);
|
|
||||||
Array.Reverse (Lines);
|
|
||||||
|
|
||||||
TreeIter Iter;
|
|
||||||
for (int i = 0; i < 25 && i < Lines.Length; i++) {
|
|
||||||
|
|
||||||
string Line = Lines [i];
|
|
||||||
if (Line.Contains (SelectedEmail)) {
|
|
||||||
|
|
||||||
// Look for the snowman!
|
|
||||||
string [] Parts = Regex.Split (Line, "☃");
|
|
||||||
string Message = Parts [1];
|
|
||||||
string UserName = Parts [2];
|
|
||||||
string TimeAgo = Parts [3];
|
|
||||||
string UserEmail = Parts [4];
|
|
||||||
|
|
||||||
Iter = LogStore.Append ();
|
|
||||||
|
|
||||||
LogStore.SetValue (Iter, 0, SparkleHelpers.GetAvatar (UserEmail, 24));
|
|
||||||
|
|
||||||
if (SparkleRepo.UserEmail.Equals (UserEmail)) {
|
|
||||||
|
|
||||||
LogStore.SetValue (Iter, 1, "<b>You</b>\n" + Message.Replace ("/", " → "));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
LogStore.SetValue (Iter, 1, "<b>" + UserName + "</b>\n" + Message.Replace ("/", " → "));
|
|
||||||
}
|
|
||||||
|
|
||||||
LogStore.SetValue (Iter, 2, TimeAgo + " ");
|
|
||||||
|
|
||||||
// We're not showing email, it's only
|
|
||||||
// there for lookup purposes
|
|
||||||
LogStore.SetValue (Iter, 3, UserEmail);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TreeView LogView = new TreeView (LogStore);
|
|
||||||
LogView.HeadersVisible = false;
|
|
||||||
|
|
||||||
CellRendererText TextCellRight = new Gtk.CellRendererText ();
|
|
||||||
TextCellRight.Xalign = 1;
|
|
||||||
|
|
||||||
LogView.AppendColumn ("", new Gtk.CellRendererPixbuf (), "pixbuf", 0);
|
|
||||||
|
|
||||||
CellRendererText CellRendererMarkup = new CellRendererText ();
|
|
||||||
TreeViewColumn ColumnMarkup = new TreeViewColumn ();
|
|
||||||
ColumnMarkup.PackStart (CellRendererMarkup, true);
|
|
||||||
LogView.AppendColumn (ColumnMarkup);
|
|
||||||
|
|
||||||
ColumnMarkup.SetCellDataFunc (CellRendererMarkup, new Gtk.TreeCellDataFunc (RenderRow));
|
|
||||||
|
|
||||||
LogView.AppendColumn (ColumnMarkup);
|
|
||||||
LogView.AppendColumn ("", TextCellRight, "text", 2);
|
|
||||||
|
|
||||||
TreeViewColumn [] Columns = LogView.Columns;
|
|
||||||
Columns [0].MinWidth = 42;
|
|
||||||
Columns [1].Expand = true;
|
|
||||||
Columns [2].Expand = true;
|
|
||||||
Columns [1].MinWidth = 350;
|
|
||||||
Columns [2].MinWidth = 50;
|
|
||||||
|
|
||||||
Columns [2].Spacing = 200;
|
|
||||||
LogView.CursorChanged += delegate (object o, EventArgs args) {
|
|
||||||
TreeModel Model;
|
|
||||||
if (LogView.Selection.GetSelected (out Model, out Iter)) {
|
|
||||||
SelectedEmail = (string) Model.GetValue (Iter, 3);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compose an e-mail when a row is activated
|
|
||||||
LogView.RowActivated +=
|
|
||||||
delegate (object o, RowActivatedArgs Args) {
|
|
||||||
switch (SparklePlatform.Name) {
|
|
||||||
case "GNOME":
|
|
||||||
Process.StartInfo.FileName = "xdg-open";
|
|
||||||
break;
|
|
||||||
case "OSX":
|
|
||||||
Process.StartInfo.FileName = "open";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Process.StartInfo.Arguments = "mailto:" + SelectedEmail;
|
|
||||||
Process.Start ();
|
|
||||||
};
|
|
||||||
|
|
||||||
LogScrolledWindow = new ScrolledWindow ();
|
|
||||||
LogScrolledWindow.AddWithViewport (LogView);
|
|
||||||
|
|
||||||
return LogScrolledWindow;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renders a row with custom markup
|
|
||||||
private void RenderRow (TreeViewColumn Column, CellRenderer Cell, TreeModel Model, TreeIter Iter)
|
|
||||||
{
|
|
||||||
|
|
||||||
string Item = (string) Model.GetValue (Iter, 1);
|
|
||||||
(Cell as CellRendererText).Markup = Item;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue