Warn the user for speed issues when uploading certain types of images

This commit is contained in:
Hylke Bons 2010-06-20 22:05:11 +01:00
parent 98db7aca7d
commit bf78e39f74
2 changed files with 489 additions and 8 deletions

View file

@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using Gtk;
using Mono.Unix;
using System;
using System.IO;
using System.Net;
@ -27,6 +28,11 @@ namespace SparkleShare {
public static class SparkleHelpers
{
public static string _ (string s)
{
return Catalog.GetString (s);
}
// Get's the avatar for a specific email address and size
public static Gdk.Pixbuf GetAvatar (string Email, int Size)
{
@ -151,52 +157,65 @@ namespace SparkleShare {
if (time_span <= TimeSpan.FromSeconds (60)) {
if (time_span.Seconds > 1)
return string.Format ("{0} seconds ago", time_span.Seconds);
return string.Format (_("{0} seconds ago"), time_span.Seconds);
else
return "a second ago";
}
if (time_span <= TimeSpan.FromSeconds (60)) {
if (time_span.Minutes > 1)
return string.Format ("about {0} minutes ago", time_span.Minutes);
return string.Format (_("about {0} minutes ago"), time_span.Minutes);
else
return "a minute ago";
}
if (time_span <= TimeSpan.FromHours(24)) {
if (time_span.Hours > 1)
return string.Format ("about {0} minutes ago", time_span.Hours);
return string.Format (_("about {0} minutes ago"), time_span.Hours);
else
return "about an hour ago";
}
if (time_span <= TimeSpan.FromDays(30)) {
if (time_span.Days > 1)
return string.Format ("{0} days ago", time_span.Days);
return string.Format (_("{0} days ago"), time_span.Days);
else
return "yesterday";
}
if (time_span <= TimeSpan.FromDays(365)) {
if (time_span.Days > 1)
return string.Format ("{0} months ago", (int) time_span.Days / 30);
return string.Format (_("{0} months ago"), (int) time_span.Days / 30);
else
return "a month ago";
}
if (time_span <= TimeSpan.FromDays(365)) {
if (time_span.Days > 1)
return string.Format ("{0} months ago", (int) time_span.Days / 365);
return string.Format (_("{0} months ago"), (int) time_span.Days / 365);
else
return "a month ago";
}
if (time_span.Days > 365)
return string.Format ("{0} months ago", (int) time_span.Days / 365);
return string.Format (_("{0} months ago"), (int) time_span.Days / 365);
else
return "a year ago";
}
}
// Checks for unicorns
public static void CheckForUnicorns (string s) {
s = s.ToLower ();
if (s.Contains ("unicorn") && (s.Contains (".png") || s.Contains (".jpg"))) {
string title = _("Hold your ponies!");
string subtext = _("SparkleShare is known to be insanely fast with \n" +
"pictures of unicorns. Please make sure your internets\n" +
"are upgraded to the latest version to avoid problems.");
SparkleBubble unicorn_bubble = new SparkleBubble (title, subtext);
unicorn_bubble.Show ();
}
}
}

462
SparkleShare/SparkleRepo.cs Normal file
View file

@ -0,0 +1,462 @@
// 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;
private bool HasChanged = false;
private DateTime LastChange;
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.Interval = 4000;
BufferTimer.Elapsed += delegate (object o, ElapsedEventArgs args) {
SparkleHelpers.DebugInfo ("Buffer", "[" + Name + "] Checking for changes.");
if (HasChanged) {
SparkleHelpers.DebugInfo ("Buffer", "[" + Name + "] Changes found, checking if settled.");
DateTime now = DateTime.UtcNow;
TimeSpan changed = new TimeSpan (now.Ticks - LastChange.Ticks);
if (changed.TotalMilliseconds > 5000) {
HasChanged = false;
SparkleHelpers.DebugInfo ("Buffer", "[" + Name + "] Changes have settled, adding.");
AddCommitAndPush ();
}
}
};
BufferTimer.Start ();
// Add everything that changed
// since SparkleShare was stopped
AddCommitAndPush ();
SparkleHelpers.DebugInfo ("Git", "[" + Name + "] Nothing going on...");
}
// Starts a time buffer when something changes
private void OnFileActivity (object o, FileSystemEventArgs args)
{
WatcherChangeTypes wct = args.ChangeType;
if (!ShouldIgnore (args.Name)) {
SparkleHelpers.DebugInfo ("Event", "[" + Name + "] " + wct.ToString () + " '" + args.Name + "'");
FetchTimer.Stop ();
LastChange = DateTime.UtcNow;
HasChanged = true;
}
}
// When there are changes we generally want to Add, Commit and Push
// so this method does them all with appropriate timers, etc switched off
public void AddCommitAndPush ()
{
BufferTimer.Stop ();
FetchTimer.Stop ();
Add ();
string Message = FormatCommitMessage ();
if (!Message.Equals ("")) {
Commit (Message);
Fetch ();
Push ();
}
FetchTimer.Start ();
BufferTimer.Start ();
SparkleHelpers.CheckForUnicorns (Message);
}
// Stages the made changes
private void Add ()
{
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 ();
}
// 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, 32);
// 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.
private 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
private 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 () +
"\nand " + (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 () +
"\nand " + (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 () +
"\nand " + (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 "";
}
}
}