feature<SSH>: supports using ssh private key to access remote git repository

This commit is contained in:
leo 2021-10-12 17:14:48 +08:00
parent 306292147f
commit 75a46ceb74
11 changed files with 200 additions and 18 deletions

View file

@ -11,6 +11,7 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition x:Name="rowSSHKey" Height="0"/>
<RowDefinition Height="32"/>
<RowDefinition Height="32"/>
<RowDefinition Height="32"/>
@ -31,7 +32,8 @@
Grid.Row="0" Grid.Column="1"
x:Name="txtUrl"
Height="24"
Placeholder="{DynamicResource Text.Clone.RemoteURL.Placeholder}">
Placeholder="{DynamicResource Text.Clone.RemoteURL.Placeholder}"
TextChanged="OnUrlChanged">
<controls:TextEdit.Text>
<Binding ElementName="me" Path="Uri" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay">
<Binding.ValidationRules>
@ -43,7 +45,7 @@
<TextBlock
Grid.Row="1" Grid.Column="0"
Text="{DynamicResource Text.Clone.Folder}"
Text="{DynamicResource Text.SSHKey}"
Margin="0,0,4,0"
HorizontalAlignment="Right"/>
<Grid Grid.Row="1" Grid.Column="1">
@ -52,6 +54,33 @@
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<controls:TextEdit
Grid.Column="0"
x:Name="txtSSHKey"
Height="24"
Placeholder="{DynamicResource Text.SSHKey.Placeholder}"/>
<controls:IconButton
Grid.Column="1"
Click="OnSelectSSHKey"
Width="24" Height="24"
Margin="2,0,0,0" Padding="4"
BorderBrush="{DynamicResource Brush.Border1}"
BorderThickness="1"
Icon="{StaticResource Icon.Folder.Open}"/>
</Grid>
<TextBlock
Grid.Row="2" Grid.Column="0"
Text="{DynamicResource Text.Clone.Folder}"
Margin="0,0,4,0"
HorizontalAlignment="Right"/>
<Grid Grid.Row="2" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<controls:TextEdit
Grid.Column="0"
x:Name="txtFolder"
@ -77,12 +106,12 @@
</Grid>
<TextBlock
Grid.Row="2" Grid.Column="0"
Grid.Row="3" Grid.Column="0"
Text="{DynamicResource Text.Clone.LocalName}"
Margin="0,0,4,0"
HorizontalAlignment="Right"/>
<controls:TextEdit
Grid.Row="2" Grid.Column="1"
Grid.Row="3" Grid.Column="1"
Height="24"
x:Name="txtLocal"
Placeholder="{DynamicResource Text.Clone.LocalName.Placeholder}">
@ -96,12 +125,12 @@
</controls:TextEdit>
<TextBlock
Grid.Row="3" Grid.Column="0"
Grid.Row="4" Grid.Column="0"
Text="{DynamicResource Text.Clone.RemoteName}"
Margin="0,0,4,0"
HorizontalAlignment="Right"/>
<controls:TextEdit
Grid.Row="3" Grid.Column="1"
Grid.Row="4" Grid.Column="1"
x:Name="txtRemote"
Height="24"
Placeholder="{DynamicResource Text.Clone.RemoteName.Placeholder}">
@ -115,12 +144,12 @@
</controls:TextEdit>
<TextBlock
Grid.Row="4" Grid.Column="0"
Grid.Row="5" Grid.Column="0"
Text="{DynamicResource Text.Clone.AdditionalParam}"
Margin="0,0,4,0"
HorizontalAlignment="Right"/>
<controls:TextEdit
Grid.Row="4" Grid.Column="1"
Grid.Row="5" Grid.Column="1"
Height="24"
Placeholder="{DynamicResource Text.Clone.AdditionalParam.Placeholder}"
Text="{Binding ElementName=me, Path=ExtraArgs, Mode=TwoWay}"/>

View file

@ -1,5 +1,8 @@
using Microsoft.Win32;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace SourceGit.Views.Popups {
@ -32,11 +35,13 @@ namespace SourceGit.Views.Popups {
if (Validation.GetHasError(edit)) return null;
}
var sshKey = txtSSHKey.Text;
return Task.Run(() => {
var extras = string.IsNullOrEmpty(ExtraArgs) ? "" : ExtraArgs;
if (!string.IsNullOrEmpty(RemoteName)) extras += $" --origin {RemoteName}";
var succ = new Commands.Clone(Folder, Uri, LocalName, extras, UpdateProgress).Exec();
var succ = new Commands.Clone(Folder, Uri, LocalName, sshKey, extras, UpdateProgress).Exec();
if (!succ) return false;
var path = Folder;
@ -53,6 +58,13 @@ namespace SourceGit.Views.Popups {
return false;
}
if (!string.IsNullOrEmpty(sshKey)) {
var config = new Commands.Config(path);
var remote = "origin";
if (!string.IsNullOrEmpty(RemoteName)) remote = RemoteName;
config.Set($"remote.{remote}.sshkey", sshKey);
}
var gitDir = new Commands.QueryGitDir(path).Result();
var repo = Models.Preference.Instance.AddRepository(path, gitDir, "");
if (repo != null) Dispatcher.Invoke(() => Models.Watcher.Open(repo));
@ -60,12 +72,34 @@ namespace SourceGit.Views.Popups {
});
}
private void OnFolderSelectorClick(object sender, System.Windows.RoutedEventArgs e) {
private void OnFolderSelectorClick(object sender, RoutedEventArgs e) {
var dialog = new Controls.FolderDialog();
if (dialog.ShowDialog() == true) {
Folder = dialog.SelectedPath;
txtFolder.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
}
}
private void OnSelectSSHKey(object sender, RoutedEventArgs e) {
var initPath = Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "..", ".ssh"));
if (!Directory.Exists(initPath)) Directory.CreateDirectory(initPath);
var dialog = new OpenFileDialog();
dialog.Filter = $"SSH Private Key|*";
dialog.Title = App.Text("SSHKey");
dialog.InitialDirectory = initPath;
dialog.CheckFileExists = true;
dialog.Multiselect = false;
if (dialog.ShowDialog() == true) txtSSHKey.Text = dialog.FileName;
}
private void OnUrlChanged(object sender, TextChangedEventArgs e) {
if (!string.IsNullOrEmpty(txtUrl.Text)) {
rowSSHKey.Height = new GridLength(txtUrl.Text.StartsWith("git@") ? 32 : 0, GridUnitType.Pixel);
} else {
rowSSHKey.Height = new GridLength(0, GridUnitType.Pixel);
}
}
}
}

View file

@ -28,13 +28,21 @@ namespace SourceGit.Views.Popups {
public override Task<bool> Start() {
var prune = chkPrune.IsChecked == true;
var remote = (remotes.SelectedItem as Models.Remote).Name;
if (chkFetchAll.IsChecked == true) remote = "--all";
var all = chkFetchAll.IsChecked == true;
return Task.Run(() => {
Models.Watcher.SetEnabled(repo, false);
var succ = new Commands.Fetch(repo, remote, prune, UpdateProgress).Exec();
if (all) {
foreach (var r in remotes.ItemsSource) {
new Commands.Fetch(repo, (r as Models.Remote).Name, prune, UpdateProgress).Exec();
}
} else {
new Commands.Fetch(repo, remote, prune, UpdateProgress).Exec();
}
Models.Watcher.SetEnabled(repo, true);
return succ;
return true;
});
}
}

View file

@ -13,6 +13,7 @@
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="32"/>
<RowDefinition x:Name="rowSSHKey" Height="0"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
@ -48,6 +49,7 @@
Grid.Row="1" Grid.Column="1"
x:Name="txtUrl"
Height="24"
TextChanged="OnUrlChanged"
Placeholder="{DynamicResource Text.Remote.URL.Placeholder}">
<controls:TextEdit.Text>
<Binding ElementName="me" Path="RemoteURL" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay">
@ -57,5 +59,32 @@
</Binding>
</controls:TextEdit.Text>
</controls:TextEdit>
<TextBlock
Grid.Row="2" Grid.Column="0"
Text="{DynamicResource Text.SSHKey}"
Margin="0,0,4,0"
HorizontalAlignment="Right"/>
<Grid Grid.Row="2" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<controls:TextEdit
Grid.Column="0"
x:Name="txtSSHKey"
Height="24"
Placeholder="{DynamicResource Text.SSHKey.Placeholder}"/>
<controls:IconButton
Grid.Column="1"
Click="OnSelectSSHKey"
Width="24" Height="24"
Margin="2,0,0,0" Padding="4"
BorderBrush="{DynamicResource Brush.Border1}"
BorderThickness="1"
Icon="{StaticResource Icon.Folder.Open}"/>
</Grid>
</Grid>
</controls:PopupWidget>

View file

@ -1,4 +1,8 @@
using Microsoft.Win32;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace SourceGit.Views.Popups {
@ -24,6 +28,11 @@ namespace SourceGit.Views.Popups {
InitializeComponent();
ruleName.Repo = repo;
if (RemoteURL.StartsWith("git@")) {
txtSSHKey.Text = new Commands.Config(repo.Path).Get($"remote.{remote.Name}.sshkey");
} else {
txtSSHKey.Text = "";
}
}
public override string GetTitle() {
@ -39,11 +48,17 @@ namespace SourceGit.Views.Popups {
txtUrl.GetBindingExpression(TextBox.TextProperty).UpdateSource();
if (Validation.GetHasError(txtUrl)) return null;
var sshKey = txtSSHKey.Text;
return Task.Run(() => {
Models.Watcher.SetEnabled(repo.Path, false);
if (remote == null) {
var succ = new Commands.Remote(repo.Path).Add(RemoteName, RemoteURL);
if (succ) new Commands.Fetch(repo.Path, RemoteName, true, UpdateProgress).Exec();
if (!string.IsNullOrEmpty(sshKey)) {
new Commands.Config(repo.Path).Set($"remote.{RemoteName}.sshkey", sshKey);
}
} else {
if (remote.URL != RemoteURL) {
var succ = new Commands.Remote(repo.Path).SetURL(remote.Name, RemoteURL);
@ -54,10 +69,36 @@ namespace SourceGit.Views.Popups {
var succ = new Commands.Remote(repo.Path).Rename(remote.Name, RemoteName);
if (succ) remote.Name = RemoteName;
}
if (!string.IsNullOrEmpty(sshKey)) {
new Commands.Config(repo.Path).Set($"remote.{RemoteName}.sshkey", sshKey);
}
}
Models.Watcher.SetEnabled(repo.Path, true);
return true;
});
}
private void OnSelectSSHKey(object sender, RoutedEventArgs e) {
var initPath = Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "..", ".ssh"));
if (!Directory.Exists(initPath)) Directory.CreateDirectory(initPath);
var dialog = new OpenFileDialog();
dialog.Filter = $"SSH Private Key|*";
dialog.Title = App.Text("SSHKey");
dialog.InitialDirectory = initPath;
dialog.CheckFileExists = true;
dialog.Multiselect = false;
if (dialog.ShowDialog() == true) txtSSHKey.Text = dialog.FileName;
}
private void OnUrlChanged(object sender, TextChangedEventArgs e) {
if (!string.IsNullOrEmpty(txtUrl.Text)) {
rowSSHKey.Height = new GridLength(txtUrl.Text.StartsWith("git@") ? 32 : 0, GridUnitType.Pixel);
} else {
rowSSHKey.Height = new GridLength(0, GridUnitType.Pixel);
}
}
}
}