Skip to content

Commit 3b9f55f

Browse files
committed
feature: using setsid to support terminating clone/fetch/pull/push on Linux gracefully
Signed-off-by: leo <longshuang@msn.cn>
1 parent 4fca32f commit 3b9f55f

5 files changed

Lines changed: 38 additions & 29 deletions

File tree

src/Commands/Command.cs

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,36 @@ protected async Task<Result> ReadToEndAsync()
158158

159159
protected ProcessStartInfo CreateGitStartInfo(bool redirect)
160160
{
161+
var useSetSid = OperatingSystem.IsLinux() && CancellationToken.CanBeCanceled;
162+
var selfExecFile = Environment.ProcessPath;
163+
var builder = new StringBuilder(2048);
164+
165+
if (useSetSid)
166+
builder.Append(Native.OS.GitExecutable.Quoted()).Append(' ');
167+
168+
builder
169+
.Append("--no-pager -c core.quotepath=off -c credential.helper=")
170+
.Append(Native.OS.CredentialHelper)
171+
.Append(' ');
172+
173+
switch (Editor)
174+
{
175+
case EditorType.CoreEditor:
176+
builder.Append($"""-c core.editor="\"{selfExecFile}\" --core-editor" """);
177+
break;
178+
case EditorType.RebaseEditor:
179+
builder.Append($"""-c core.editor="\"{selfExecFile}\" --rebase-message-editor" -c sequence.editor="\"{selfExecFile}\" --rebase-todo-editor" -c rebase.abbreviateCommands=true """);
180+
break;
181+
default:
182+
builder.Append("-c core.editor=true ");
183+
break;
184+
}
185+
186+
builder.Append(Args);
187+
161188
var start = new ProcessStartInfo();
162-
start.FileName = Native.OS.GitExecutable;
189+
start.FileName = useSetSid ? "setsid" : Native.OS.GitExecutable;
190+
start.Arguments = builder.ToString();
163191
start.UseShellExecute = false;
164192
start.CreateNoWindow = true;
165193

@@ -172,7 +200,6 @@ protected ProcessStartInfo CreateGitStartInfo(bool redirect)
172200
}
173201

174202
// Force using this app as SSH askpass program
175-
var selfExecFile = Environment.ProcessPath;
176203
start.Environment.Add("SSH_ASKPASS", selfExecFile); // Can not use parameter here, because it invoked by SSH with `exec`
177204
start.Environment.Add("SSH_ASKPASS_REQUIRE", "prefer");
178205
start.Environment.Add("SOURCEGIT_LAUNCH_AS_ASKPASS", "TRUE");
@@ -190,28 +217,6 @@ protected ProcessStartInfo CreateGitStartInfo(bool redirect)
190217
start.Environment.Add("LC_ALL", "C");
191218
}
192219

193-
var builder = new StringBuilder(2048);
194-
builder
195-
.Append("--no-pager -c core.quotepath=off -c credential.helper=")
196-
.Append(Native.OS.CredentialHelper)
197-
.Append(' ');
198-
199-
switch (Editor)
200-
{
201-
case EditorType.CoreEditor:
202-
builder.Append($"""-c core.editor="\"{selfExecFile}\" --core-editor" """);
203-
break;
204-
case EditorType.RebaseEditor:
205-
builder.Append($"""-c core.editor="\"{selfExecFile}\" --rebase-message-editor" -c sequence.editor="\"{selfExecFile}\" --rebase-todo-editor" -c rebase.abbreviateCommands=true """);
206-
break;
207-
default:
208-
builder.Append("-c core.editor=true ");
209-
break;
210-
}
211-
212-
builder.Append(Args);
213-
start.Arguments = builder.ToString();
214-
215220
// Working directory
216221
if (!string.IsNullOrEmpty(WorkingDirectory))
217222
start.WorkingDirectory = WorkingDirectory;

src/Native/Linux.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.IO;
5+
using System.Runtime.InteropServices;
56
using System.Runtime.Versioning;
67

78
using Avalonia;
@@ -13,6 +14,9 @@ namespace SourceGit.Native
1314
[SupportedOSPlatform("linux")]
1415
internal class Linux : OS.IBackend
1516
{
17+
[DllImport("libc", SetLastError = true)]
18+
private static extern int kill(int pid, int sig);
19+
1620
public void SetupApp(AppBuilder builder)
1721
{
1822
builder.With(new X11PlatformOptions() { EnableIme = true });
@@ -140,7 +144,8 @@ public void OpenWithDefaultEditor(string file)
140144

141145
public void TerminateProcess(Process proc)
142146
{
143-
proc.Kill(true);
147+
if (kill(-proc.Id, 15) != 0)
148+
proc.Kill(true); // Fallback to force kill if the process is not terminated by SIGTERM
144149
}
145150

146151
private string FindExecutable(string filename)

src/ViewModels/Clone.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public override async Task<bool> Sure()
120120
.WithCancellation(token)
121121
.Use(log)
122122
.ExecAsync();
123-
if (!succ)
123+
if (!succ || token.IsCancellationRequested)
124124
return false;
125125

126126
var path = _parentFolder;

src/ViewModels/CommitDetail.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,6 @@ private void Refresh()
514514
Task.Run(async () =>
515515
{
516516
var changes = await new Commands.CompareRevisions(_repo.FullPath, _commit.FirstParentToCompare, _commit.SHA)
517-
.WithCancellation(token)
518517
.ReadAsync()
519518
.ConfigureAwait(false);
520519

src/ViewModels/Popup.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ public bool CanTerminate
1212
get => _canTerminate;
1313
protected set
1414
{
15-
// Terminating a process is only supported on Windows.
16-
if (OperatingSystem.IsWindows())
15+
// Terminating a process is only supported on Windows/Linux.
16+
if (!OperatingSystem.IsMacOS())
1717
SetProperty(ref _canTerminate, value);
1818
}
1919
}

0 commit comments

Comments
 (0)