Actually grab the repo name fro mthe entry in Add dialog

This commit is contained in:
Hylke Bons 2010-05-19 21:47:43 +01:00
parent 1e04bade71
commit a55232f29d
17 changed files with 74 additions and 1701 deletions

13
AUTHORS
View file

@ -1,6 +1,11 @@
Maintainer:
Hylke Bons <hylkebons@gmail.com>
Artwork by:
Lapo Calamandrei <calamandrei@gmail.com>
Jakub Steiner <jimmac@novell.com>
Hylke Bons <hylkebons@gmail.com>
Contributions by:
Lapo Calamandrei <calamandrei@gmail.com>
Garrett LeSage <garrett@novell.com>
Andreas Nilsson <andreasn@gnome.org>
Jakub Steiner <jimmac@novell.com>

54
LICENSE
View file

@ -619,57 +619,3 @@ Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

19
README
View file

@ -1,18 +1,17 @@
SparkleShare Version 0.0.12
SparkleShare Version 0.0.14
===========================
SparkleShare is a file sharing and collaboration tool inspired by Dropbox. It
allows you to instantly sync with any Git repository you have access to.
SparkleShare is a file sharing and collaboration tool inspired by Dropbox.
SparkleShare isn't just a piece of software, it's part of your workflow. It's
designed to make sharing documents and collaboration easier, and to make peers
aware of what you are doing. The user interface and features are made to
support this goal. However, you may find SparkleShare useful for other kinds of
purposes as well, like backing up files or monitoring your favourite project.
SparkleShare is not made to be a graphical frontend for git or a backup tool
In contrast to the projects name, we will very likely
refuse to implement your personal ponies. :)
aware of what you are doing. It allows you to instantly sync with any Git
repository you have access to. The user interface and features are made to
support this goal. Though SparkleShare is not made to be a graphical frontend
for git or a backup tool, it may be useful for other kinds of purposes as well,
like backing up small files or monitoring your favourite project. In contrast
to the projects name, we will very likely refuse to implement your personal
ponies. :)
SparkleShare currently only works on Linux/GNOME.
Windows and OSX ports are planned for the future.

56
SparkleShare Normal file
View file

@ -0,0 +1,56 @@
#!/bin/bash
# Create a directory to save the pid to
mkdir -p /tmp/sparkleshare/
if [[ "$1" == "start" ]]; then
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" == "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,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,174 +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;
private Entry NameEntry;
public SparkleDialog () : base ("") {
BorderWidth = 6;
IconName = "folder-sparkleshare";
Modal = true;
Resizable = false;
SetPosition (WindowPosition.Center);
Title = _("Add a Folder");
VBox VBox = new VBox (false, 0);
Label NameLabel = new Label (_("Folder Name: "));
NameEntry = new Entry ();
Label NameExample = new Label (_("<span size='small'><i>Example: ") +
_("Project.</i></span>"));
NameExample.UseMarkup = true;
NameExample.SetAlignment (0, 0);
NameLabel.Xalign = 1;
Label RemoteUrlLabel = new Label (_("Remote address: "));
string [] DefaultUrls = new string [4] { "ssh://git@github.com",
"ssh://git@git.gnome.org",
"ssh://git@fedorahosted.org",
"ssh://git@gitorious.org" };
RemoteUrlCombo = new ComboBoxEntry (DefaultUrls);
Label RemoteUrlExample = new Label (_("<span size='small'><i>Example: ") +
_("ssh://git@github.com.</i></span>"));
RemoteUrlExample.UseMarkup = true;
RemoteUrlExample.SetAlignment (0, 0);
RemoteUrlLabel.Xalign = 1;
HButtonBox ButtonBox = new HButtonBox ();
ButtonBox.Layout = ButtonBoxStyle.End;
ButtonBox.Spacing = 6;
ButtonBox.BorderWidth = 6;
AddButton = new Button (Stock.Add);
Button CancelButton = new Button (Stock.Cancel);
CancelButton.Clicked += delegate {
Destroy ();
};
RemoteUrlCombo.Entry.Changed += CheckFields;
NameEntry.Changed += CheckFields;
AddButton.Sensitive = false;
AddButton.Clicked += CloneRepo;
ButtonBox.Add (CancelButton);
ButtonBox.Add (AddButton);
Table Table = new Table(4, 2, false);
Table.RowSpacing = 6;
Table.BorderWidth = 6;
Table.Attach (NameLabel, 0, 1, 0, 1);
Table.Attach (NameEntry, 1, 2, 0, 1);
Table.Attach (NameExample, 1, 2, 1, 2);
Table.Attach (RemoteUrlLabel, 0, 1, 3, 4);
Table.Attach (RemoteUrlCombo, 1, 2, 3, 4);
Table.Attach (RemoteUrlExample, 1, 2, 4, 5);
VBox.PackStart (Table, false, false, 0);
VBox.PackStart (ButtonBox, false, false, 0);
Add (VBox);
ShowAll ();
}
public void CloneRepo (object o, EventArgs args) {
Remove (Child);
VBox Box = new VBox (false, 24);
SparkleSpinner Spinner = new SparkleSpinner ();
Label Label = new Label (_("Downloading files,\n") +
_("this may take a while..."));
Box.PackStart (Spinner, false, false, 0);
Box.PackStart (Label, false, false, 0);
BorderWidth = 30;
Add (Box);
string RepoRemoteUrl = RemoteUrlCombo.Entry.Text;
string RepoName = NameEntry.Text;
Process Process = new Process();
Process.EnableRaisingEvents = true;
Process.StartInfo.RedirectStandardOutput = true;
Process.StartInfo.UseShellExecute = false;
Process.StartInfo.FileName = "git";
Process.StartInfo.WorkingDirectory =
SparklePaths.SparkleTmpPath;
Process.StartInfo.Arguments =
"clone " + SparkleHelpers.CombineMore (RepoRemoteUrl, RepoName)
.Substring (2);
Process.Start ();
Process.Exited += delegate {
Directory.Move (
SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath,
RepoName),
SparkleHelpers.CombineMore (SparklePaths.SparklePath,
RepoName)
);
// Enable notifications and synchronisation by default
File.Create (SparkleHelpers.CombineMore (SparklePaths.SparklePath,
RepoName, ".git",
"sparkleshare.notify"));
File.Create (SparkleHelpers.CombineMore (SparklePaths.SparklePath,
RepoName, ".git",
"sparkleshare.sync"));
Destroy ();
};
}
// Enables the Add button when the fields are
// filled in correctly
public void CheckFields (object o, EventArgs args) {
if (SparkleHelpers.IsGitUrl (RemoteUrlCombo.Entry.Text)
&& NameEntry.Text.Length > 0)
AddButton.Sensitive = true;
else
AddButton.Sensitive = false;
}
}
}

View file

@ -1,105 +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 {
public static Gdk.Pixbuf GetAvatar (string Email, int Size) {
string AvatarPath = Path.Combine (SparklePaths.SparkleAvatarPath,
Size + "x" + Size);
if (!Directory.Exists (AvatarPath)) {
Directory.CreateDirectory (AvatarPath);
Console.WriteLine ("[Config] Created '" + AvatarPath + "'");
}
string AvatarFilePath = 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 = SparklePaths.SparkleTmpPath + Email + Size;
if (!File.Exists (TmpFile)) {
WebClient.DownloadFileAsync (GravatarUri, TmpFile);
WebClient.DownloadFileCompleted += delegate {
File.Delete (AvatarPath + Email);
FileInfo TmpFileInfo = new FileInfo (TmpFile);
if (TmpFileInfo.Length > 255)
File.Move (TmpFile, AvatarPath + Email);
};
}
if (File.Exists (AvatarPath + Email))
return new Gdk.Pixbuf (AvatarPath + Email);
else
return GetIcon ("avatar-default", Size);
}
}
// Creates an MD5 hash
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 (SparklePaths.SparkleInstallPath);
return SparkleTheme.LoadIcon (Name, Size,
IconLookupFlags.GenericFallback);
}
public static bool IsGitUrl (string Url) {
return Regex.Match (Url, @"[a-z]+://(.)+").Success;
}
}
}

View file

@ -1,45 +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 System;
using System.IO;
namespace SparkleShare {
public static class SparklePaths {
public static string SparkleTmpPath = "/tmp/sparkleshare";
public static string HomePath =
Environment.GetEnvironmentVariable("HOME");
public static string SparklePath = Path.Combine (HomePath ,"SparkleShare");
public static string SparkleConfigPath =
SparkleHelpers.CombineMore (HomePath, ".config", "sparkleshare");
public static string SparkleInstallPath =
SparkleHelpers.CombineMore ("usr", "share", "sparkleshare",
"icons", "hicolor");
public static string SparkleAvatarPath =
Path.Combine (SparkleConfigPath, "avatars");
public static string SparkleIconPath = "/usr/share/icons/hicolor";
}
}

View file

@ -1,28 +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 System;
namespace SparkleShare {
public static class SparklePlatform {
// Detect OSX, Windows, GNOME or KDE here
public static string Name = "GNOME";
}
}

View file

@ -1,403 +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 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 SparkleRepo (string RepoPath) {
Process = new Process();
Process.EnableRaisingEvents = false;
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"
UserName = "Anonymous";
Process.StartInfo.FileName = "git";
Process.StartInfo.Arguments = "config --get user.name";
Process.Start();
UserName = Process.StandardOutput.ReadToEnd().Trim ();
// 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 = 17500;
FetchTimer.Elapsed += delegate {
Fetch ();
};
FetchTimer.Start();
BufferTimer = new Timer ();
// Add everything that changed
// since SparkleShare was stopped
Add ();
Console.WriteLine ("[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)) {
Console.WriteLine ("[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) {
Console.WriteLine ("[Buffer][" + Name + "] Done waiting.");
Add ();
};
Console.WriteLine ("[Buffer][" + Name + "] " +
"Waiting for more changes...");
BufferTimer.Start();
} else {
// Extend the delay when something changes
BufferTimer.Close ();
BufferTimer = new Timer ();
BufferTimer.Interval = Interval;
BufferTimer.Elapsed += delegate (object o, ElapsedEventArgs args) {
Console.WriteLine ("[Buffer][" + Name + "] Done waiting.");
Add ();
};
FetchTimer.Start ();
BufferTimer.Start();
Console.WriteLine ("[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 ();
Console.WriteLine ("[Git][" + Name + "] Staging changes...");
Process.StartInfo.Arguments = "add --all";
Process.Start();
Process.WaitForExit ();
Console.WriteLine ("[Git][" + Name + "] Changes staged.");
// SparkleUI.NotificationIcon.SetSyncingState ();
string Message = FormatCommitMessage ();
if (!Message.Equals ("")) {
Commit (Message);
Push ();
Fetch ();
// Push again in case of a conflict
Push ();
}
}
// Commits the made changes
public void Commit (string Message) {
Console.WriteLine ("[Commit][" + Name + "] " + Message);
Console.WriteLine ("[Git][" + Name + "] Commiting changes...");
Process.StartInfo.Arguments = "commit -m \"" + Message + "\"";
Process.Start();
Process.WaitForExit ();
Console.WriteLine ("[Git][" + Name + "] Changes commited.");
}
// Fetches changes from the remote repo
public void Fetch () {
FetchTimer.Stop ();
// SparkleUI.NotificationIcon.SetSyncingState ();
Console.WriteLine ("[Git][" + Name + "] Fetching changes... ");
Process.StartInfo.Arguments = "fetch -v";
Process.Start();
string Output = Process.StandardOutput.ReadToEnd().Trim (); // TODO: This doesn't work :(
Process.WaitForExit ();
Console.WriteLine ("[Git][" + Name + "] Changes fetched.");
if (!Output.Contains ("up to date"))
Merge ();
// SparkleUI.NotificationIcon.SetIdleState ();
FetchTimer.Start ();
}
// Merges the fetched changes
public void Merge () {
// Watcher.EnableRaisingEvents = false;
Console.WriteLine ("[Git][" + Name + "] Merging fetched changes... ");
Process.StartInfo.Arguments = "merge origin/master";
Process.Start();
Process.WaitForExit ();
Console.WriteLine ("[Git][" + Name + "] Changes merged.");
string Output = Process.StandardOutput.ReadToEnd().Trim ();
// Show notification if there are updates
if (!Output.Equals ("Already up-to-date.")) {
// 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))
ShowEventBubble (LastCommitUserName + " " + LastCommitMessage,
SparkleHelpers.GetAvatar (LastCommitEmail, 48),
true);
}
// Watcher.EnableRaisingEvents = true;
Console.WriteLine ("[Git][" + Name + "] Nothing going on... ");
}
// Pushes the changes to the remote repo
public void Push () {
Console.WriteLine ("[Git][" + Name + "] Pushing changes...");
Process.StartInfo.Arguments = "push";
Process.Start();
Process.WaitForExit ();
Console.WriteLine ("[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 "";
}
// Shows a notification with text and image
public void ShowEventBubble (string Title,
Gdk.Pixbuf Avatar,
bool ShowButtons) {
SparkleBubble StuffChangedBubble = new SparkleBubble (Title, "");
StuffChangedBubble.Icon = Avatar;
// Add a button to open the folder where the changed file is
if (ShowButtons)
StuffChangedBubble.AddAction ("", "Open Folder",
delegate {
Process.StartInfo.FileName = "xdg-open";
Process.StartInfo.Arguments = LocalPath;
Process.Start();
Process.StartInfo.FileName = "git";
} );
}
}
}

View file

@ -1,105 +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
Process.StartInfo.FileName = "whoami";
Process.Start();
if (Process.StandardOutput.ReadToEnd().Trim ().Equals ("root")) {
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,49 +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="notify-sharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=2df29c54e245917a" />
<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>
</Project>

Binary file not shown.

View file

@ -1,91 +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.Timers;
namespace SparkleShare {
// This is a close implementation of GtkSpinner
public class SparkleSpinner : Image {
public bool Active;
private Gdk.Pixbuf [] Images;
private Timer Timer;
private int CycleDuration;
private int CurrentStep;
private int NumSteps;
private int Size;
public SparkleSpinner () : base () {
CycleDuration = 750;
CurrentStep = 0;
Size = 48;
Gdk.Pixbuf SpinnerGallery = SparkleHelpers.GetIcon ("process-working",
Size);
int FramesInWidth = SpinnerGallery.Width / Size;
int FramesInHeight = SpinnerGallery.Height / Size;
NumSteps = FramesInWidth * FramesInHeight;
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 { NextImage (); };
Start ();
}
private void NextImage () {
if (CurrentStep < NumSteps)
CurrentStep++;
else
CurrentStep = 0;
Pixbuf = Images [CurrentStep];
}
public bool IsActive () {
return Active;
}
public void Start () {
CurrentStep = 0;
Active = true;
Timer.Start ();
}
public void Stop () {
Active = false;
Timer.Stop ();
}
}
}

View file

@ -1,145 +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.IO;
using System.Diagnostics;
namespace SparkleShare {
public class SparkleStatusIcon : StatusIcon {
// Short alias for the translations
public static string _ (string s) {
return Catalog.GetString (s);
}
public SparkleStatusIcon () : base () {
Activate += delegate {
Menu Menu = new Menu();
MenuItem StatusItem = new MenuItem (_("Everything is up to date"));
StatusItem.Sensitive = false;
Menu.Add (StatusItem);
Menu.Add (new SeparatorMenuItem ());
MenuItem [] FolderItems =
new MenuItem [SparkleShare.Repositories.Length];
// TODO: For some strange reason both entries
// open the same repo...
int i = 0;
foreach (SparkleRepo SparkleRepo in SparkleShare.Repositories) {
FolderItems [i] = new MenuItem (SparkleRepo.Name);
FolderItems [i].Activated += delegate {
SparkleWindow SparkleWindow = new SparkleWindow (SparkleRepo);
SparkleWindow.ShowAll ();
};
Menu.Add (FolderItems [i]);
i++;
}
MenuItem AddItem = new MenuItem (_("Add a 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 OpenFolderItem = new MenuItem (_("Open Sharing Folder"));
OpenFolderItem.Activated += delegate {
Process Process = new Process ();
Process.StartInfo.FileName = "xdg-open";
Process.StartInfo.Arguments = SparklePaths.SparklePath;
Process.Start();
};
Menu.Add (OpenFolderItem);
MenuItem AboutItem = new MenuItem (_("Visit SparkleShare Website"));
AboutItem.Activated += delegate {
Process Process = new Process ();
Process.StartInfo.FileName = "xdg-open";
Process.StartInfo.Arguments = "http://www.sparkleshare.org/";
Process.Start();
};
Menu.Add (AboutItem);
Menu.Add (new SeparatorMenuItem ());
MenuItem QuitItem = new MenuItem ("Quit");
QuitItem.Activated += delegate { Environment.Exit (0); };
Menu.Add (QuitItem);
Menu.ShowAll ();
Menu.Popup ();
};
SetIdleState ();
}
public void SetIdleState () {
IconName = "folder-sparkleshare";
}
public void SetSyncingState () {
// IconName = "folder-syncing";
}
public void SetErrorState () {
// IconName = "folder-sync-error";
}
// 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,156 +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 SparkleShare;
using System;
using System.Diagnostics;
using System.IO;
namespace SparkleShare {
public class SparkleUI {
public static SparkleStatusIcon NotificationIcon;
public SparkleUI (bool HideUI) {
Process Process = new Process();
Process.EnableRaisingEvents = false;
Process.StartInfo.RedirectStandardOutput = true;
Process.StartInfo.UseShellExecute = false;
string SparklePath = SparklePaths.SparklePath;
// Create 'SparkleShare' folder in the user's home folder
// if it's not there already
if (!Directory.Exists (SparklePath)) {
Directory.CreateDirectory (SparklePath);
Console.WriteLine ("[Config] Created '" + SparklePath + "'");
if (SparklePlatform.Name.Equals ("GNOME")) {
// Add a special icon to the SparkleShare folder
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();
// Add the SparkleShare folder to the bookmarks
string BookmarksFileName =
Path.Combine (SparklePaths.HomePath, ".gtk-bookmarks");
if (File.Exists (BookmarksFileName)) {
TextWriter TextWriter = File.AppendText (BookmarksFileName);
TextWriter.WriteLine ("file://" + SparklePath + " SparkleShare");
TextWriter.Close();
}
}
}
// Get all the repos in ~/SparkleShare
SparkleRepo [] TmpRepos =
new SparkleRepo [Directory.GetDirectories (SparklePath).Length];
int i = 0;
foreach (string Folder in Directory.GetDirectories (SparklePath)) {
// Check if the folder is a git repo
if (Directory.Exists (SparkleHelpers.CombineMore (Folder,
".git"))) {
TmpRepos [i] = new SparkleRepo (Folder);
i++;
// Attach emblems
if (SparklePlatform.Name.Equals ("GNOME")) {
Process.StartInfo.FileName = "gvfs-set-attribute";
Process.StartInfo.Arguments = " file://" + Folder +
" metadata::emblems " +
"[synced]";
Process.Start();
}
}
}
SparkleShare.Repositories = new SparkleRepo [i];
Array.Copy (TmpRepos, SparkleShare.Repositories, i);
// Don't create the window and status
// icon when --disable-gui was given
if (!HideUI) {
// Create the status icon
NotificationIcon = new SparkleStatusIcon ();
// 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.\n" +
"Please create some in " +
"the SparkleShare folder.");
NoFoldersBubble.IconName = "folder-sparkleshare";
NoFoldersBubble.AddAction ("", "Open SparkleShare Folder", delegate {
Process.StartInfo.FileName = "xdg-open";
Process.StartInfo.Arguments = SparklePaths.SparklePath;
Process.Start();
} );
}
}
// 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;
Console.WriteLine ("[Event][SparkleShare] " + wct.ToString() +
" '" + args.Name + "'");
SparkleDialog SparkleDialog = new SparkleDialog ();
SparkleDialog.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);
Console.WriteLine ("[Config] Created '" + ConfigPath + "'");
// Create a place to store the avatars
Directory.CreateDirectory (AvatarPath);
Console.WriteLine ("[Config] Created '" + AvatarPath + "avatars'");
}
}
}
}

View file

@ -1,300 +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 LayoutHorizontal;
private ScrolledWindow LogScrolledWindow;
private ScrolledWindow PeopleScrolledWindow;
private string SelectedEmail;
public SparkleWindow (SparkleRepo Repo) : base ("") {
SparkleRepo = Repo;
SelectedEmail = "";
SetSizeRequest (720, 540);
SetPosition (WindowPosition.Center);
BorderWidth = 6;
Title = _("" + SparkleRepo.Name + " on " +
SparkleRepo.RemoteOriginUrl
.TrimEnd (("/" + SparkleRepo.Name).ToCharArray ()));
IconName = "folder-sparkleshare";
VBox LayoutVertical = new VBox (false, 0);
LayoutHorizontal = new VBox (false, 6);
LayoutHorizontal.BorderWidth = 6;
LayoutHorizontal.PackStart (CreatePeopleList (), false, false, 0);
LayoutHorizontal.PackStart (CreateEventLog (), true, true, 0);
LayoutVertical.PackStart (LayoutHorizontal, true, true, 0);
HButtonBox DialogButtons = new HButtonBox ();
DialogButtons.Layout = ButtonBoxStyle.End;
DialogButtons.BorderWidth = 6;
Button CloseButton = new Button (Stock.Close);
CloseButton.Clicked += delegate (object o, EventArgs args) {
Destroy ();
};
DialogButtons.Add (CloseButton);
LayoutVertical.PackStart (DialogButtons, false, false, 0);
/* Timer RedrawTimer = new Timer ();
RedrawTimer.Interval = 5000;
RedrawTimer.Elapsed += delegate {
UpdatePeopleList ();
UpdateEventLog ();
};
RedrawTimer.Start();
*/
Add (LayoutVertical);
}
public void UpdateEventLog () {
LayoutHorizontal.Remove (LogScrolledWindow);
LogScrolledWindow = CreateEventLog ();
LayoutHorizontal.PackStart (LogScrolledWindow, true, true, 0);
ShowAll ();
}
public void UpdatePeopleList () {
LayoutHorizontal.Remove (PeopleScrolledWindow);
PeopleScrolledWindow = CreatePeopleList ();
LayoutHorizontal.PackStart (PeopleScrolledWindow, false, false, 0);
LayoutHorizontal.ReorderChild (PeopleScrolledWindow, 0);
ShowAll ();
}
public ScrolledWindow CreateEventLog () {
ListStore LogStore = new ListStore (typeof (Gdk.Pixbuf),
typeof (string),
typeof (string),
typeof (string));
Process Process = new Process();
Process.EnableRaisingEvents = false;
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☃%an %s☃%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 TimeAgo = Parts [2];
string UserEmail = Parts [3];
string IconFile = "document-edited";
if (Message.IndexOf (" added ") > -1)
IconFile = "document-added";
if (Message.IndexOf (" deleted ") > -1)
IconFile = "document-removed";
if (Message.IndexOf (" moved ") > -1 ||
Message.IndexOf (" renamed ") > -1)
IconFile = "document-moved";
Gdk.Pixbuf ChangeIcon = SparkleHelpers.GetIcon (IconFile, 16);
Iter = LogStore.Append ();
LogStore.SetValue (Iter, 0, ChangeIcon);
LogStore.SetValue (Iter, 1, Message);
LogStore.SetValue (Iter, 2, " " + TimeAgo);
// We're not showing e-mail, 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.Alignment = Pango.Alignment.Right;
CellRendererText TextCellMiddle = new Gtk.CellRendererText ();
TextCellMiddle.Ellipsize = Pango.EllipsizeMode.End;
LogView.AppendColumn ("", new Gtk.CellRendererPixbuf (), "pixbuf", 0);
LogView.AppendColumn ("", TextCellMiddle, "text", 1);
LogView.AppendColumn ("", TextCellRight, "text", 2);
TreeViewColumn [] Columns = LogView.Columns;
Columns [0].MinWidth = 32;
Columns [1].Expand = true;
Columns [1].MaxWidth = 150;
LogView.CursorChanged += delegate(object o, EventArgs args) {
TreeModel model;
if (LogView.Selection.GetSelected (out model, out Iter)) {
SelectedEmail = (string) LogStore.GetValue (Iter, 3);
UpdatePeopleList ();
}
};
LogScrolledWindow = new ScrolledWindow ();
LogScrolledWindow.AddWithViewport (LogView);
return LogScrolledWindow;
}
// Creates a visual list of people working in the repo
public ScrolledWindow CreatePeopleList () {
Process Process = new Process ();
Process.EnableRaisingEvents = false;
Process.StartInfo.RedirectStandardOutput = true;
Process.StartInfo.UseShellExecute = false;
// Get a log of commits, example: "Hylke Bons☃added 'file'."
Process.StartInfo.FileName = "git";
Process.StartInfo.Arguments = "log --format=\"%an☃%ae\" -50";
Process.StartInfo.WorkingDirectory = SparkleRepo.LocalPath;
Process.Start();
string Output = Process.StandardOutput.ReadToEnd().Trim ();
string [] People = new string [50];
string [] Lines = Regex.Split (Output, "\n");
ListStore PeopleStore = new ListStore (typeof (Gdk.Pixbuf),
typeof (string),
typeof (string));
int i = 0;
TreeIter Iter;
TreePath TreePath = new TreePath ();
foreach (string Line in Lines) {
// Only add name if it isn't there already
if (Array.IndexOf (People, Line) == -1) {
People [i] = Line;
string [] Parts = Regex.Split (Line, "☃");
string UserName = Parts [0];
string UserEmail = Parts [1];
// Do something special if the person is you
if (UserEmail.Equals (SparkleRepo.UserEmail))
UserName += _(" (thats you!)");
// Actually add to the list
Iter = PeopleStore.Prepend ();
PeopleStore.SetValue (Iter, 0,
SparkleHelpers.GetAvatar (UserEmail , 32));
PeopleStore.SetValue (Iter, 1,
"<b>" + UserName + "</b>\n" +
"<span font_size=\"smaller\">" +
UserEmail + "</span>");
PeopleStore.SetValue (Iter, 2, UserEmail);
if (UserEmail.Equals (SelectedEmail)) {
TreePath = PeopleStore.GetPath (Iter);
}
}
i++;
}
IconView PeopleView = new IconView (PeopleStore);
PeopleView.PixbufColumn = 0;
PeopleView.MarkupColumn = 1;
PeopleView.Columns = 3;
PeopleView.Spacing = 6;
PeopleView.ItemWidth = 200;
PeopleView.Orientation = Orientation.Horizontal;
PeopleView.SelectionMode = SelectionMode.Single;
// TODO: doesn't work. Always seems to select the
// first row :(
PeopleView.SelectPath (TreePath);
PeopleView.SelectionChanged += delegate (object o, EventArgs args) {
if (PeopleView.SelectedItems.Length > 0) {
PeopleStore.GetIter (out Iter, PeopleView.SelectedItems [0]);
string NewSelectedEmail = (string) PeopleStore.GetValue (Iter, 2);
if (NewSelectedEmail.Equals (SelectedEmail)) {
SelectedEmail = "";
PeopleView.UnselectAll ();
} else
SelectedEmail = NewSelectedEmail;
} else SelectedEmail = "";
UpdateEventLog ();
};
PeopleScrolledWindow = new ScrolledWindow ();
PeopleScrolledWindow.AddWithViewport (PeopleView);
PeopleScrolledWindow.HeightRequest = 200;
return PeopleScrolledWindow;
}
}
}