Fix autostart because pid already exists even though program is not running

This commit is contained in:
Steven Harms 2010-06-15 23:42:23 -04:00
parent 01647a6e4e
commit f377e03790
12 changed files with 64 additions and 1825 deletions

64
SparkleShare Normal file
View 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

View file

@ -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);
}
}
}

View file

@ -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 :(
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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");
}
}

View file

@ -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 "";
}
}
}

View file

@ -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);
}
}
}

View file

@ -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>

View file

@ -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 ();
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}