diff --git a/Sparkles/Git/GitCommand.cs b/Sparkles/Git/GitCommand.cs index 60d498ff..ba314c7d 100644 --- a/Sparkles/Git/GitCommand.cs +++ b/Sparkles/Git/GitCommand.cs @@ -93,6 +93,12 @@ namespace Sparkles.Git { SetEnvironmentVariable ("GIT_SSH_COMMAND", GIT_SSH_COMMAND); SetEnvironmentVariable ("GIT_TERMINAL_PROMPT", "0"); + + // Don't let Git try to read the config options in PREFIX/etc or ~ + SetEnvironmentVariable ("GIT_CONFIG_NOSYSTEM", "1"); + SetEnvironmentVariable ("PREFIX", ""); + SetEnvironmentVariable ("HOME", ""); + SetEnvironmentVariable ("LANG", "en_US"); } diff --git a/Sparkles/Git/GitFetcher.cs b/Sparkles/Git/GitFetcher.cs index dfbb4534..221a5af0 100644 --- a/Sparkles/Git/GitFetcher.cs +++ b/Sparkles/Git/GitFetcher.cs @@ -336,10 +336,10 @@ namespace Sparkles.Git { { string [] settings = { "core.autocrlf input", - "core.quotepath false", // Don't quote "unusual" characters in path names + "core.quotepath false", // For commands to output Unicode characters "as is". e.g. '"h\303\251"' becomes 'hé'. + "core.precomposeunicode true", // Use the same Unicode form on all filesystems "core.ignorecase false", // Be case sensitive explicitly to work on Mac "core.filemode false", // Ignore permission changes - "core.precomposeunicode true", // Use the same Unicode form on all filesystems "core.safecrlf false", "core.excludesfile \"\"", "core.packedGitLimit 128m", // Some memory limiting options @@ -440,6 +440,14 @@ namespace Sparkles.Git { git_config_required.StartAndWaitForExit (); git_config_clean.StartAndWaitForExit (); git_config_smudge.StartAndWaitForExit (); + + if (InstallationInfo.OperatingSystem != OS.Windows) { + string pre_push_hook_path = Path.Combine (TargetFolder, ".git", "hooks", "pre-push"); + + // TODO: Use proper API + var chmod = new Command ("chmod", "700 " + pre_push_hook_path); + chmod.StartAndWaitForExit (); + } } } } diff --git a/Sparkles/Git/GitRepository.cs b/Sparkles/Git/GitRepository.cs index e5425483..58247fc0 100644 --- a/Sparkles/Git/GitRepository.cs +++ b/Sparkles/Git/GitRepository.cs @@ -213,7 +213,7 @@ namespace Sparkles.Git { return false; } - string message = base.status_message.Replace ("\"", "\\\""); + string message = base.status_message; if (string.IsNullOrEmpty (message)) message = FormatCommitMessage (); @@ -387,17 +387,17 @@ namespace Sparkles.Git { // Commits the made changes void Commit (string message) { - GitCommand git; + GitCommand git_config; string user_name = base.local_config.User.Name; string user_email = base.local_config.User.Email; if (!this.user_is_set) { - git = new GitCommand (LocalPath, "config user.name \"" + user_name + "\""); - git.StartAndWaitForExit (); + git_config = new GitCommand (LocalPath, "config user.name \"" + user_name + "\""); + git_config.StartAndWaitForExit (); - git = new GitCommand (LocalPath, "config user.email \"" + user_email + "\""); - git.StartAndWaitForExit (); + git_config = new GitCommand (LocalPath, "config user.email \"" + user_email + "\""); + git_config.StartAndWaitForExit (); this.user_is_set = true; } @@ -410,11 +410,28 @@ namespace Sparkles.Git { user_email = user_email.AESEncrypt (password); } - git = new GitCommand (LocalPath, - string.Format ("commit --all --message=\"{0}\" --author=\"{1} <{2}>\"", - message, user_name, user_email)); + GitCommand git_commit; + string message_file_path = Path.Combine (LocalPath, ".git", "info", "commit_message"); - git.StartAndReadStandardOutput (); + try { + File.WriteAllText (message_file_path, message); + + // Commit from message stored in temporary file to avoid special character conflicts on the command line + git_commit = new GitCommand (LocalPath, + string.Format ("commit --all --file=\"{0}\" --author=\"{1} <{2}>\"", + message_file_path, user_name, user_email)); + + } catch (IOException e) { + Logger.LogInfo ("Git", Name + " | Could not create commit message file: " + message_file_path, e); + + // If committing with a temporary file fails, use a simple static commit message + git_commit = new GitCommand (LocalPath, + string.Format ("commit --all --message=\"{0}\" --author=\"{1} <{2}>\"", + "Changes by SparkleShare", user_name, user_email)); + } + + git_commit.StartAndReadStandardOutput (); + File.Delete (message_file_path); } @@ -502,15 +519,14 @@ namespace Sparkles.Git { // ?? unmerged, new files -> Stage the new files var git_status = new GitCommand (LocalPath, "status --porcelain"); - string output = git_status.StartAndReadStandardOutput (); + string output = git_status.StartAndReadStandardOutput (); string [] lines = output.Split ("\n".ToCharArray ()); bool trigger_conflict_event = false; foreach (string line in lines) { string conflicting_file_path = line.Substring (3); - conflicting_file_path = EnsureSpecialChars (conflicting_file_path); - conflicting_file_path = conflicting_file_path.Trim ("\"".ToCharArray ()); + conflicting_file_path = conflicting_file_path.Trim ("\"".ToCharArray ()); // Remove possible rename indicators string [] separators = {" -> \"", " -> "}; @@ -810,8 +826,7 @@ namespace Sparkles.Git { change_set.User.Name.AESDecrypt (password), change_set.User.Email.AESDecrypt (password)); - } catch (Exception e) { - Console.WriteLine (e.StackTrace); + } catch (Exception) { change_set.User = new User (match.Groups ["name"].Value, match.Groups ["email"].Value); } } @@ -892,59 +907,10 @@ namespace Sparkles.Git { change.IsFolder = true; } - try { - change.Path = EnsureSpecialChars (change.Path); - - if (change.Type == ChangeType.Moved) - change.MovedToPath = EnsureSpecialChars (change.MovedToPath); - - } catch (Exception e) { - Logger.LogInfo ("Local", string.Format ("Error parsing line due to special character: '{0}'", line), e); - return null; - } - return change; } - string EnsureSpecialChars (string path) - { - // The path is quoted if it contains special characters - if (path.StartsWith ("\"")) - path = ResolveSpecialChars (path.Substring (1, path.Length - 2)); - - return path; - } - - - string ResolveSpecialChars (string s) - { - StringBuilder builder = new StringBuilder (s.Length); - List codes = new List (); - - for (int i = 0; i < s.Length; i++) { - while (s [i] == '\\' && - s.Length - i > 3 && - char.IsNumber (s [i + 1]) && - char.IsNumber (s [i + 2]) && - char.IsNumber (s [i + 3])) { - - codes.Add (Convert.ToByte (s.Substring (i + 1, 3), 8)); - i += 4; - } - - if (codes.Count > 0) { - builder.Append (Encoding.UTF8.GetString (codes.ToArray ())); - codes.Clear (); - } - - builder.Append (s [i]); - } - - return builder.ToString (); - } - - // Git doesn't track empty directories, so this method // fills them all with a hidden empty file. // @@ -1005,7 +971,7 @@ namespace Sparkles.Git { while (!git_status.StandardOutput.EndOfStream) { string line = git_status.StandardOutput.ReadLine (); - line = line.Trim (); + line = line.Trim (); if (line.EndsWith (".empty") || line.EndsWith (".empty\"")) line = line.Replace (".empty", ""); @@ -1018,13 +984,13 @@ namespace Sparkles.Git { change = new Change () { Type = ChangeType.Moved, - Path = EnsureSpecialChars (path), - MovedToPath = EnsureSpecialChars (moved_to_path) + Path = path, + MovedToPath = moved_to_path }; } else { string path = line.Substring (2).Trim ("\" ".ToCharArray ()); - change = new Change () { Path = EnsureSpecialChars (path) }; + change = new Change () { Path = path }; change.Type = ChangeType.Added; if (line.StartsWith ("M")) { @@ -1052,8 +1018,8 @@ namespace Sparkles.Git { foreach (Change change in ParseStatus ()) { if (change.Type == ChangeType.Moved) { - message += "< ‘" + EnsureSpecialChars (change.Path) + "’\n"; - message += "> ‘" + EnsureSpecialChars (change.MovedToPath) + "’\n"; + message += "< ‘" + change.Path + "’\n"; + message += "> ‘" + change.MovedToPath + "’\n"; } else { switch (change.Type) {