Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2971 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
25 changed files with 1200 additions and 774 deletions
@ -1,282 +0,0 @@ |
|||||||
// <file>
|
|
||||||
// <copyright see="prj:///doc/copyright.txt"/>
|
|
||||||
// <license see="prj:///doc/license.txt"/>
|
|
||||||
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
|
||||||
// <version>$Revision$</version>
|
|
||||||
// </file>
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Threading; |
|
||||||
using System.Windows.Forms; |
|
||||||
|
|
||||||
using ICSharpCode.Core; |
|
||||||
using ICSharpCode.SharpDevelop.Gui; |
|
||||||
using ICSharpCode.Svn.Gui; |
|
||||||
using NSvn.Core; |
|
||||||
|
|
||||||
namespace ICSharpCode.Svn |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Description of SvnClient.
|
|
||||||
/// </summary>
|
|
||||||
public class SvnClient |
|
||||||
{ |
|
||||||
public static SvnClient Instance = new SvnClient(); |
|
||||||
|
|
||||||
Client client; |
|
||||||
string logMessage = String.Empty; |
|
||||||
|
|
||||||
|
|
||||||
MessageViewCategory svnCategory; |
|
||||||
|
|
||||||
public MessageViewCategory SvnCategory { |
|
||||||
get { |
|
||||||
if (svnCategory == null) { |
|
||||||
svnCategory = new MessageViewCategory("Subversion", "Subversion"); |
|
||||||
CompilerMessageView compilerMessageView = (CompilerMessageView)WorkbenchSingleton.Workbench.GetPad(typeof(CompilerMessageView)).PadContent; |
|
||||||
compilerMessageView.AddCategory(svnCategory); |
|
||||||
} |
|
||||||
return svnCategory; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public NSvn.Core.Client Client { |
|
||||||
get { |
|
||||||
return client; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public string LogMessage { |
|
||||||
get { |
|
||||||
return logMessage; |
|
||||||
} |
|
||||||
set { |
|
||||||
logMessage = value; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
string GetKindString(NodeKind kind) |
|
||||||
{ |
|
||||||
switch (kind) { |
|
||||||
case NodeKind.Directory: |
|
||||||
return "directory "; |
|
||||||
case NodeKind.File: |
|
||||||
return "file "; |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public static string GetActionString(ChangedPathAction action) |
|
||||||
{ |
|
||||||
switch (action) { |
|
||||||
case ChangedPathAction.Add: |
|
||||||
return GetActionString(NotifyAction.CommitAdded); |
|
||||||
case ChangedPathAction.Delete: |
|
||||||
return GetActionString(NotifyAction.CommitDeleted); |
|
||||||
case ChangedPathAction.Modify: |
|
||||||
return GetActionString(NotifyAction.CommitModified); |
|
||||||
case ChangedPathAction.Replace: |
|
||||||
return GetActionString(NotifyAction.CommitReplaced); |
|
||||||
default: |
|
||||||
return "unknown"; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static string GetActionString(NotifyAction action) |
|
||||||
{ |
|
||||||
switch (action) { |
|
||||||
case NotifyAction.Add: |
|
||||||
case NotifyAction.UpdateAdd: |
|
||||||
case NotifyAction.CommitAdded: |
|
||||||
return "added"; |
|
||||||
case NotifyAction.Copy: |
|
||||||
return "copied"; |
|
||||||
case NotifyAction.Delete: |
|
||||||
case NotifyAction.UpdateDelete: |
|
||||||
case NotifyAction.CommitDeleted: |
|
||||||
return "deleted"; |
|
||||||
case NotifyAction.Restore: |
|
||||||
return "restored"; |
|
||||||
case NotifyAction.Revert: |
|
||||||
return "reverted"; |
|
||||||
case NotifyAction.FailedRevert: |
|
||||||
return "revert failed"; |
|
||||||
case NotifyAction.Resolved: |
|
||||||
return "resolved"; |
|
||||||
case NotifyAction.Skip: |
|
||||||
return "skipped"; |
|
||||||
case NotifyAction.UpdateUpdate: |
|
||||||
return "updated"; |
|
||||||
case NotifyAction.CommitPostfixTxDelta: |
|
||||||
case NotifyAction.UpdateCompleted: |
|
||||||
return ""; |
|
||||||
case NotifyAction.UpdateExternal: |
|
||||||
return "updated external"; |
|
||||||
case NotifyAction.CommitModified: |
|
||||||
return "modified"; |
|
||||||
case NotifyAction.CommitReplaced: |
|
||||||
return "replaced"; |
|
||||||
default: |
|
||||||
return "unknown"; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void ReceiveNotification(object sender, NotificationEventArgs e) |
|
||||||
{ |
|
||||||
if (e.Action == NotifyAction.UpdateCompleted) { |
|
||||||
SvnCategory.AppendText(Environment.NewLine + "Updated " + e.Path + " to revision " + e.RevisionNumber + "."); |
|
||||||
return; |
|
||||||
} |
|
||||||
if (e.Action == NotifyAction.CommitPostfixTxDelta) { |
|
||||||
SvnCategory.AppendText("."); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
string kind = GetKindString(e.NodeKind); |
|
||||||
string action = GetActionString(e.Action); |
|
||||||
SvnCategory.AppendText(Environment.NewLine + kind + action + " : " + e.Path); |
|
||||||
} |
|
||||||
|
|
||||||
void SetLogMessage(object sender, LogMessageEventArgs e) |
|
||||||
{ |
|
||||||
if (e.Message == null) { |
|
||||||
e.Message = logMessage; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void WriteMid(string str) |
|
||||||
{ |
|
||||||
const int max = 40; |
|
||||||
string filler = new String('-', max - str.Length / 2); |
|
||||||
SvnCategory.AppendText(Environment.NewLine + filler + " " + str + " " + filler); |
|
||||||
if (str.Length % 2 == 0) { |
|
||||||
SvnCategory.AppendText("-"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
class ThreadStartWrapper |
|
||||||
{ |
|
||||||
ThreadStart innerDelegate; |
|
||||||
|
|
||||||
public ThreadStartWrapper(ThreadStart innerDelegate) |
|
||||||
{ |
|
||||||
this.innerDelegate = innerDelegate; |
|
||||||
} |
|
||||||
|
|
||||||
public void Start() |
|
||||||
{ |
|
||||||
try { |
|
||||||
innerDelegate(); |
|
||||||
} catch (ThreadAbortException) { |
|
||||||
// don't show error message, silently cancel thread
|
|
||||||
} catch (Exception e) { |
|
||||||
SvnClient.Instance.OperationDone(); |
|
||||||
|
|
||||||
MessageService.ShowError(e); |
|
||||||
} finally { |
|
||||||
SvnClient.Instance.OperationDone(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
InOperationDialog inOperationForm; |
|
||||||
bool done = false; |
|
||||||
public void OperationStart(string operationName, ThreadStart threadStart) |
|
||||||
{ |
|
||||||
done = false; |
|
||||||
WriteMid(operationName); |
|
||||||
|
|
||||||
Thread thread = new Thread(new ThreadStart(new ThreadStartWrapper(threadStart).Start)); |
|
||||||
thread.Name = "SvnOperation"; |
|
||||||
thread.IsBackground = true; |
|
||||||
inOperationForm = new InOperationDialog(operationName, thread); |
|
||||||
inOperationForm.Owner = WorkbenchSingleton.MainForm; |
|
||||||
inOperationForm.Show(); |
|
||||||
thread.Start(); |
|
||||||
} |
|
||||||
|
|
||||||
void OperationDone() |
|
||||||
{ |
|
||||||
if (done) { |
|
||||||
return; |
|
||||||
} |
|
||||||
WorkbenchSingleton.SafeThreadCall(WriteMid, "Done"); |
|
||||||
try { |
|
||||||
if (inOperationForm != null) { |
|
||||||
inOperationForm.Operation = null; |
|
||||||
WorkbenchSingleton.SafeThreadCall(inOperationForm.Close); |
|
||||||
inOperationForm = null; |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
MessageService.ShowError(e); |
|
||||||
} finally { |
|
||||||
done = true; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void WaitForOperationEnd() |
|
||||||
{ |
|
||||||
while (!done) { |
|
||||||
Application.DoEvents(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
SvnClient() |
|
||||||
{ |
|
||||||
LoggingService.Info("SVN: SvnClient initialized"); |
|
||||||
client = new Client(); |
|
||||||
client.LogMessage += new LogMessageDelegate(SetLogMessage); |
|
||||||
client.Notification += new NotificationDelegate(ReceiveNotification); |
|
||||||
|
|
||||||
client.AuthBaton.Add(AuthenticationProvider.GetUsernameProvider()); |
|
||||||
client.AuthBaton.Add(AuthenticationProvider.GetSimpleProvider()); |
|
||||||
client.AuthBaton.Add(AuthenticationProvider.GetSimplePromptProvider(new SimplePromptDelegate(this.PasswordPrompt), 3)); |
|
||||||
client.AuthBaton.Add(AuthenticationProvider.GetSslServerTrustFileProvider()); |
|
||||||
client.AuthBaton.Add(AuthenticationProvider.GetSslServerTrustPromptProvider(new SslServerTrustPromptDelegate(this.SslServerTrustPrompt))); |
|
||||||
client.AuthBaton.Add(AuthenticationProvider.GetSslClientCertPasswordFileProvider()); |
|
||||||
client.AuthBaton.Add(AuthenticationProvider.GetSslClientCertPasswordPromptProvider(new SslClientCertPasswordPromptDelegate(this.ClientCertificatePasswordPrompt), 3)); |
|
||||||
client.AuthBaton.Add(AuthenticationProvider.GetSslClientCertFileProvider()); |
|
||||||
client.AuthBaton.Add(AuthenticationProvider.GetSslClientCertPromptProvider(new SslClientCertPromptDelegate(this.ClientCertificatePrompt), 3)); |
|
||||||
} |
|
||||||
|
|
||||||
SimpleCredential PasswordPrompt(string realm, string userName, bool maySave) |
|
||||||
{ |
|
||||||
using (LoginDialog loginDialog = new LoginDialog(realm, userName, maySave)) { |
|
||||||
if (WorkbenchSingleton.SafeThreadFunction<Form, DialogResult>(loginDialog.ShowDialog, WorkbenchSingleton.MainForm) == DialogResult.OK) { |
|
||||||
return loginDialog.Credential; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
SslServerTrustCredential SslServerTrustPrompt(string realm, SslFailures failures, SslServerCertificateInfo info, bool maySave) |
|
||||||
{ |
|
||||||
using (SslServerTrustDialog sslServerTrustDialog = new SslServerTrustDialog(info, failures, maySave)) { |
|
||||||
if (WorkbenchSingleton.SafeThreadFunction<Form, DialogResult>(sslServerTrustDialog.ShowDialog, WorkbenchSingleton.MainForm) == DialogResult.OK) { |
|
||||||
return sslServerTrustDialog.Credential; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
SslClientCertificatePasswordCredential ClientCertificatePasswordPrompt(string realm, bool maySave) |
|
||||||
{ |
|
||||||
using (ClientCertPassphraseDialog clientCertPassphraseDialog = new ClientCertPassphraseDialog(realm, maySave)) { |
|
||||||
if (WorkbenchSingleton.SafeThreadFunction<Form, DialogResult>(clientCertPassphraseDialog.ShowDialog, WorkbenchSingleton.MainForm) == DialogResult.OK) { |
|
||||||
return clientCertPassphraseDialog.Credential; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
SslClientCertificateCredential ClientCertificatePrompt(string realm, bool maySave) |
|
||||||
{ |
|
||||||
using (ClientCertDialog clientCertDialog = new ClientCertDialog(realm, maySave)) { |
|
||||||
if (WorkbenchSingleton.SafeThreadFunction<Form, DialogResult>(clientCertDialog.ShowDialog, WorkbenchSingleton.MainForm) == DialogResult.OK) { |
|
||||||
return clientCertDialog.Credential; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,748 @@ |
|||||||
|
// <file>
|
||||||
|
// <copyright see="prj:///doc/copyright.txt"/>
|
||||||
|
// <license see="prj:///doc/license.txt"/>
|
||||||
|
// <author name="Daniel Grunwald"/>
|
||||||
|
// <version>$Revision$</version>
|
||||||
|
// </file>
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Threading; |
||||||
|
using System.Windows.Forms; |
||||||
|
using System.Text; |
||||||
|
using System.IO; |
||||||
|
using ICSharpCode.Core; |
||||||
|
using ICSharpCode.SharpDevelop.Gui; |
||||||
|
using ICSharpCode.Svn.Gui; |
||||||
|
using PumaCode.SvnDotNet.SubversionSharp; |
||||||
|
using PumaCode.SvnDotNet.AprSharp; |
||||||
|
using System.Runtime.Serialization; |
||||||
|
|
||||||
|
namespace ICSharpCode.Svn |
||||||
|
{ |
||||||
|
using Svn = PumaCode.SvnDotNet.SubversionSharp.Svn; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A wrapper around the subversion library.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SvnClientWrapper : IDisposable |
||||||
|
{ |
||||||
|
#region status->string conversion
|
||||||
|
static string GetKindString(Svn.NodeKind kind) |
||||||
|
{ |
||||||
|
switch (kind) { |
||||||
|
case Svn.NodeKind.Dir: |
||||||
|
return "directory "; |
||||||
|
case Svn.NodeKind.File: |
||||||
|
return "file "; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public static string GetActionString(char action) |
||||||
|
{ |
||||||
|
switch (action) { |
||||||
|
case 'A': |
||||||
|
return GetActionString(SvnWcNotify.Actions.CommitAdded); |
||||||
|
case 'D': |
||||||
|
return GetActionString(SvnWcNotify.Actions.CommitDeleted); |
||||||
|
case 'M': |
||||||
|
return GetActionString(SvnWcNotify.Actions.CommitModified); |
||||||
|
case 'R': |
||||||
|
return GetActionString(SvnWcNotify.Actions.CommitReplaced); |
||||||
|
default: |
||||||
|
return "unknown"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static string GetActionString(SvnWcNotify.Actions action) |
||||||
|
{ |
||||||
|
switch (action) { |
||||||
|
case SvnWcNotify.Actions.Add: |
||||||
|
case SvnWcNotify.Actions.UpdateAdd: |
||||||
|
case SvnWcNotify.Actions.CommitAdded: |
||||||
|
return "added"; |
||||||
|
case SvnWcNotify.Actions.Copy: |
||||||
|
return "copied"; |
||||||
|
case SvnWcNotify.Actions.Delete: |
||||||
|
case SvnWcNotify.Actions.UpdateDelete: |
||||||
|
case SvnWcNotify.Actions.CommitDeleted: |
||||||
|
return "deleted"; |
||||||
|
case SvnWcNotify.Actions.Restore: |
||||||
|
return "restored"; |
||||||
|
case SvnWcNotify.Actions.Revert: |
||||||
|
return "reverted"; |
||||||
|
case SvnWcNotify.Actions.FailedRevert: |
||||||
|
return "revert failed"; |
||||||
|
case SvnWcNotify.Actions.Resolved: |
||||||
|
return "resolved"; |
||||||
|
case SvnWcNotify.Actions.Skip: |
||||||
|
return "skipped"; |
||||||
|
case SvnWcNotify.Actions.UpdateUpdate: |
||||||
|
return "updated"; |
||||||
|
case SvnWcNotify.Actions.UpdateCompleted: |
||||||
|
return ""; |
||||||
|
case SvnWcNotify.Actions.UpdateExternal: |
||||||
|
return "updated external"; |
||||||
|
case SvnWcNotify.Actions.CommitModified: |
||||||
|
return "modified"; |
||||||
|
case SvnWcNotify.Actions.CommitReplaced: |
||||||
|
return "replaced"; |
||||||
|
default: |
||||||
|
return "unknown"; |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region stuff that does not belong here
|
||||||
|
/* |
||||||
|
void ReceiveNotification(object sender, SvnWcNotify e) |
||||||
|
{ |
||||||
|
if (e.Action == NotifyAction.UpdateCompleted) { |
||||||
|
SvnCategory.AppendText(Environment.NewLine + "Updated " + e.Path.ToString() + " to revision " + e.Revision + "."); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
string kind = GetKindString(e.NodeKind); |
||||||
|
string action = GetActionString(e.Action); |
||||||
|
SvnCategory.AppendText(Environment.NewLine + kind + action + " : " + e.Path); |
||||||
|
} |
||||||
|
|
||||||
|
void WriteMid(string str) |
||||||
|
{ |
||||||
|
const int max = 40; |
||||||
|
string filler = new String('-', max - str.Length / 2); |
||||||
|
SvnCategory.AppendText(Environment.NewLine + filler + " " + str + " " + filler); |
||||||
|
if (str.Length % 2 == 0) { |
||||||
|
SvnCategory.AppendText("-"); |
||||||
|
} |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
/* |
||||||
|
class ThreadStartWrapper |
||||||
|
{ |
||||||
|
ThreadStart innerDelegate; |
||||||
|
|
||||||
|
public ThreadStartWrapper(ThreadStart innerDelegate) |
||||||
|
{ |
||||||
|
this.innerDelegate = innerDelegate; |
||||||
|
} |
||||||
|
|
||||||
|
public void Start() |
||||||
|
{ |
||||||
|
try { |
||||||
|
innerDelegate(); |
||||||
|
} catch (ThreadAbortException) { |
||||||
|
// don't show error message, silently cancel thread
|
||||||
|
} catch (Exception e) { |
||||||
|
SvnClient.Instance.OperationDone(); |
||||||
|
|
||||||
|
MessageService.ShowError(e); |
||||||
|
} finally { |
||||||
|
SvnClient.Instance.OperationDone(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
InOperationDialog inOperationForm; |
||||||
|
bool done = false; |
||||||
|
public void OperationStart(string operationName, ThreadStart threadStart) |
||||||
|
{ |
||||||
|
done = false; |
||||||
|
WriteMid(operationName); |
||||||
|
|
||||||
|
Thread thread = new Thread(new ThreadStart(new ThreadStartWrapper(threadStart).Start)); |
||||||
|
thread.Name = "SvnOperation"; |
||||||
|
thread.IsBackground = true; |
||||||
|
inOperationForm = new InOperationDialog(operationName, thread); |
||||||
|
inOperationForm.Owner = WorkbenchSingleton.MainForm; |
||||||
|
inOperationForm.Show(); |
||||||
|
thread.Start(); |
||||||
|
} |
||||||
|
|
||||||
|
void OperationDone() |
||||||
|
{ |
||||||
|
if (done) { |
||||||
|
return; |
||||||
|
} |
||||||
|
WorkbenchSingleton.SafeThreadCall(WriteMid, "Done"); |
||||||
|
try { |
||||||
|
if (inOperationForm != null) { |
||||||
|
inOperationForm.Operation = null; |
||||||
|
WorkbenchSingleton.SafeThreadCall(inOperationForm.Close); |
||||||
|
inOperationForm = null; |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
MessageService.ShowError(e); |
||||||
|
} finally { |
||||||
|
done = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void WaitForOperationEnd() |
||||||
|
{ |
||||||
|
while (!done) { |
||||||
|
Application.DoEvents(); |
||||||
|
} |
||||||
|
} |
||||||
|
*/ |
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region AprPoolHandle
|
||||||
|
sealed class AprPoolHandle : IDisposable |
||||||
|
{ |
||||||
|
AprPool pool; |
||||||
|
|
||||||
|
public AprPool Pool { |
||||||
|
get { return pool; } |
||||||
|
} |
||||||
|
|
||||||
|
public AprPoolHandle() |
||||||
|
{ |
||||||
|
pool = Svn.PoolCreate(); |
||||||
|
} |
||||||
|
|
||||||
|
public void Dispose() |
||||||
|
{ |
||||||
|
if (!pool.IsNull) { |
||||||
|
pool.Destroy(); |
||||||
|
} |
||||||
|
GC.SuppressFinalize(this); |
||||||
|
} |
||||||
|
|
||||||
|
~AprPoolHandle() |
||||||
|
{ |
||||||
|
if (!pool.IsNull) { |
||||||
|
pool.Destroy(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
AprPoolHandle memoryPool; |
||||||
|
SvnClient client; |
||||||
|
Dictionary<string, Status> statusCache = new Dictionary<string, Status>(); |
||||||
|
|
||||||
|
public SvnClientWrapper() |
||||||
|
{ |
||||||
|
Debug("SVN: Create SvnClient instance"); |
||||||
|
|
||||||
|
memoryPool = new AprPoolHandle(); |
||||||
|
client = new SvnClient(memoryPool.Pool); |
||||||
|
//client.LogMessage += new LogMessageDelegate(SetLogMessage);
|
||||||
|
//client.Notification += new NotificationDelegate(ReceiveNotification);
|
||||||
|
} |
||||||
|
|
||||||
|
public void Dispose() |
||||||
|
{ |
||||||
|
if (memoryPool != null) { |
||||||
|
Debug("SVN: Dispose SvnClient"); |
||||||
|
memoryPool.Dispose(); |
||||||
|
memoryPool = null; |
||||||
|
} |
||||||
|
client = null; |
||||||
|
statusCache = null; |
||||||
|
} |
||||||
|
|
||||||
|
#region Authorization
|
||||||
|
bool authorizationEnabled; |
||||||
|
bool allowInteractiveAuthorization; |
||||||
|
|
||||||
|
public bool AllowInteractiveAuthorization { |
||||||
|
get { |
||||||
|
return allowInteractiveAuthorization; |
||||||
|
} |
||||||
|
set { |
||||||
|
CheckNotDisposed(); |
||||||
|
if (allowInteractiveAuthorization != value) { |
||||||
|
if (authorizationEnabled) |
||||||
|
throw new InvalidOperationException("Cannot change AllowInteractiveAuthorization after an operation was done."); |
||||||
|
allowInteractiveAuthorization = value; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void OpenAuth() |
||||||
|
{ |
||||||
|
if (authorizationEnabled) |
||||||
|
return; |
||||||
|
authorizationEnabled = true; |
||||||
|
|
||||||
|
const int retryLimit = 3; |
||||||
|
client.AddUsernameProvider(); |
||||||
|
client.AddSimpleProvider(); |
||||||
|
if (allowInteractiveAuthorization) { |
||||||
|
client.AddPromptProvider(PasswordPrompt, IntPtr.Zero, retryLimit); |
||||||
|
} |
||||||
|
client.AddSslServerTrustFileProvider(); |
||||||
|
if (allowInteractiveAuthorization) { |
||||||
|
client.AddPromptProvider(SslServerTrustPrompt, IntPtr.Zero); |
||||||
|
} |
||||||
|
client.AddSslClientCertPwFileProvider(); |
||||||
|
if (allowInteractiveAuthorization) { |
||||||
|
client.AddPromptProvider(ClientCertificatePasswordPrompt, IntPtr.Zero, retryLimit); |
||||||
|
} |
||||||
|
client.AddSslClientCertFileProvider(); |
||||||
|
if (allowInteractiveAuthorization) { |
||||||
|
client.AddPromptProvider(ClientCertificatePrompt, IntPtr.Zero, retryLimit); |
||||||
|
} |
||||||
|
client.OpenAuth(); |
||||||
|
} |
||||||
|
|
||||||
|
SvnError PasswordPrompt(out SvnAuthCredSimple cred, IntPtr baton, AprString realm, AprString username, bool maySave, AprPool pool) |
||||||
|
{ |
||||||
|
cred = IntPtr.Zero; |
||||||
|
LoggingService.Debug("PasswordPrompt"); |
||||||
|
try { |
||||||
|
using (LoginDialog loginDialog = new LoginDialog(realm.Value, username.Value, maySave)) { |
||||||
|
if (WorkbenchSingleton.SafeThreadFunction<Form, DialogResult>(loginDialog.ShowDialog, WorkbenchSingleton.MainForm) == DialogResult.OK) { |
||||||
|
cred = loginDialog.CreateCredential(pool); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception ex) { |
||||||
|
MessageService.ShowError(ex); |
||||||
|
} |
||||||
|
return SvnError.NoError; |
||||||
|
} |
||||||
|
|
||||||
|
SvnError SslServerTrustPrompt(out SvnAuthCredSslServerTrust cred, IntPtr baton, AprString realm, SvnAuthCredSslServerTrust.CertFailures failures, SvnAuthSslServerCertInfo certInfo, bool maySave, IntPtr pool) |
||||||
|
{ |
||||||
|
cred = IntPtr.Zero; |
||||||
|
LoggingService.Debug("SslServerTrustPrompt"); |
||||||
|
try { |
||||||
|
using (SslServerTrustDialog sslServerTrustDialog = new SslServerTrustDialog(certInfo, failures, maySave)) { |
||||||
|
if (WorkbenchSingleton.SafeThreadFunction<Form, DialogResult>(sslServerTrustDialog.ShowDialog, WorkbenchSingleton.MainForm) == DialogResult.OK) { |
||||||
|
cred = sslServerTrustDialog.CreateCredential(pool); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception ex) { |
||||||
|
MessageService.ShowError(ex); |
||||||
|
} |
||||||
|
return SvnError.NoError; |
||||||
|
} |
||||||
|
|
||||||
|
SvnError ClientCertificatePasswordPrompt(out SvnAuthCredSslClientCertPw cred, IntPtr baton, AprString realm, bool maySave, IntPtr pool) |
||||||
|
{ |
||||||
|
cred = IntPtr.Zero; |
||||||
|
LoggingService.Debug("SslServerTrustPrompt"); |
||||||
|
try { |
||||||
|
using (ClientCertPassphraseDialog clientCertPassphraseDialog = new ClientCertPassphraseDialog(realm.Value, maySave)) { |
||||||
|
if (WorkbenchSingleton.SafeThreadFunction<Form, DialogResult>(clientCertPassphraseDialog.ShowDialog, WorkbenchSingleton.MainForm) == DialogResult.OK) { |
||||||
|
cred = clientCertPassphraseDialog.CreateCredential(pool); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception ex) { |
||||||
|
MessageService.ShowError(ex); |
||||||
|
} |
||||||
|
return SvnError.NoError; |
||||||
|
} |
||||||
|
|
||||||
|
SvnError ClientCertificatePrompt(out SvnAuthCredSslClientCert cred, IntPtr baton, AprString realm, bool maySave, IntPtr pool) |
||||||
|
{ |
||||||
|
cred = IntPtr.Zero; |
||||||
|
LoggingService.Debug("SslServerTrustPrompt"); |
||||||
|
try { |
||||||
|
using (ClientCertDialog clientCertDialog = new ClientCertDialog(realm.Value, maySave)) { |
||||||
|
if (WorkbenchSingleton.SafeThreadFunction<Form, DialogResult>(clientCertDialog.ShowDialog, WorkbenchSingleton.MainForm) == DialogResult.OK) { |
||||||
|
cred = clientCertDialog.CreateCredential(pool); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception ex) { |
||||||
|
MessageService.ShowError(ex); |
||||||
|
} |
||||||
|
return SvnError.NoError; |
||||||
|
} |
||||||
|
#endregion
|
||||||
|
|
||||||
|
[System.Diagnostics.ConditionalAttribute("DEBUG")] |
||||||
|
void Debug(string text) |
||||||
|
{ |
||||||
|
LoggingService.Debug(text); |
||||||
|
} |
||||||
|
|
||||||
|
void CheckNotDisposed() |
||||||
|
{ |
||||||
|
if (client == null) |
||||||
|
throw new ObjectDisposedException("SvnClientWrapper"); |
||||||
|
} |
||||||
|
|
||||||
|
void BeforeOperation() |
||||||
|
{ |
||||||
|
// before any subversion operation, ensure the object is not disposed
|
||||||
|
// and register authorization if necessary
|
||||||
|
CheckNotDisposed(); |
||||||
|
OpenAuth(); |
||||||
|
} |
||||||
|
|
||||||
|
void AfterOperation() |
||||||
|
{ |
||||||
|
// after any subversion operation, clear the memory pool
|
||||||
|
client.Clear(); |
||||||
|
} |
||||||
|
|
||||||
|
public void ClearStatusCache() |
||||||
|
{ |
||||||
|
CheckNotDisposed(); |
||||||
|
statusCache.Clear(); |
||||||
|
} |
||||||
|
|
||||||
|
public Status SingleStatus(string filename) |
||||||
|
{ |
||||||
|
Debug("SVN: SingleStatus(" + filename + ")"); |
||||||
|
BeforeOperation(); |
||||||
|
try { |
||||||
|
filename = FileUtility.NormalizePath(filename); |
||||||
|
Status result; |
||||||
|
if (statusCache.TryGetValue(filename, out result)) { |
||||||
|
Debug("SVN: SingleStatus retrieved from cache " + result.TextStatus); |
||||||
|
return result; |
||||||
|
} |
||||||
|
client.Status2( |
||||||
|
filename, Svn.Revision.Working, |
||||||
|
delegate (IntPtr baton, SvnPath path, SvnWcStatus2 status) { |
||||||
|
string dir = path.Value; |
||||||
|
Debug("SVN: SingleStatus.callback(" + dir + "," + status.TextStatus + ")"); |
||||||
|
Status s = new Status { |
||||||
|
Copied = status.Copied, |
||||||
|
TextStatus = ToStatusKind(status.TextStatus) |
||||||
|
}; |
||||||
|
statusCache[dir] = s; |
||||||
|
if (StringComparer.InvariantCultureIgnoreCase.Equals(filename, dir)) { |
||||||
|
result = s; |
||||||
|
} |
||||||
|
}, |
||||||
|
IntPtr.Zero, |
||||||
|
false, true, false, false, false |
||||||
|
); |
||||||
|
return result; |
||||||
|
} catch (SvnException ex) { |
||||||
|
throw new SvnClientException(ex); |
||||||
|
} finally { |
||||||
|
AfterOperation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void Add(string filename, Recurse recurse) |
||||||
|
{ |
||||||
|
Debug("SVN: Add(" + filename + ", " + recurse + ")"); |
||||||
|
BeforeOperation(); |
||||||
|
try { |
||||||
|
client.Add3(filename, recurse == Recurse.Full, false, false); |
||||||
|
} catch (SvnException ex) { |
||||||
|
throw new SvnClientException(ex); |
||||||
|
} finally { |
||||||
|
AfterOperation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public string GetPropertyValue(string fileName, string propertyName) |
||||||
|
{ |
||||||
|
Debug("SVN: GetPropertyValue(" + fileName + ", " + propertyName + ")"); |
||||||
|
BeforeOperation(); |
||||||
|
try { |
||||||
|
AprHash hash = client.PropGet2(propertyName, fileName, |
||||||
|
Svn.Revision.Working, Svn.Revision.Working, |
||||||
|
false); |
||||||
|
foreach (AprHashEntry entry in hash) { |
||||||
|
// entry.ValueAsString treats the value as const char*, but it is a svn_string_t*
|
||||||
|
SvnString value = entry.Value; |
||||||
|
Debug("SVN: GetPropertyValue hash entry: (" + entry.KeyAsString + ", " + value + ")"); |
||||||
|
return value.Data.Value; |
||||||
|
} |
||||||
|
Debug("SVN: GetPropertyValue did not find any entries"); |
||||||
|
return null; |
||||||
|
} catch (SvnException ex) { |
||||||
|
throw new SvnClientException(ex); |
||||||
|
} finally { |
||||||
|
AfterOperation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void SetPropertyValue(string fileName, string propertyName, string newPropertyValue) |
||||||
|
{ |
||||||
|
Debug("SVN: SetPropertyValue(" + fileName + ", " + propertyName + ", " + newPropertyValue + ")"); |
||||||
|
BeforeOperation(); |
||||||
|
try { |
||||||
|
SvnString npv; |
||||||
|
if (newPropertyValue != null) |
||||||
|
npv = new SvnString(newPropertyValue, client.Pool); |
||||||
|
else |
||||||
|
npv = IntPtr.Zero; |
||||||
|
client.PropSet2(propertyName, npv, fileName, false, false); |
||||||
|
} catch (SvnException ex) { |
||||||
|
throw new SvnClientException(ex); |
||||||
|
} finally { |
||||||
|
AfterOperation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
SvnPath[] ToSvnPaths(string[] files) |
||||||
|
{ |
||||||
|
SvnPath[] paths = new SvnPath[files.Length]; |
||||||
|
for (int i = 0; i < files.Length; i++) { |
||||||
|
paths[i] = new SvnPath(files[i], client.Pool); |
||||||
|
} |
||||||
|
return paths; |
||||||
|
} |
||||||
|
|
||||||
|
public void Delete(string[] files, bool force) |
||||||
|
{ |
||||||
|
Debug("SVN: Delete(" + string.Join(",", files) + ", " + force + ")"); |
||||||
|
BeforeOperation(); |
||||||
|
try { |
||||||
|
client.Delete2(ToSvnPaths(files), force); |
||||||
|
} catch (SvnException ex) { |
||||||
|
throw new SvnClientException(ex); |
||||||
|
} finally { |
||||||
|
AfterOperation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void Revert(string[] files, Recurse recurse) |
||||||
|
{ |
||||||
|
Debug("SVN: Revert(" + string.Join(",", files) + ", " + recurse + ")"); |
||||||
|
BeforeOperation(); |
||||||
|
try { |
||||||
|
client.Revert(ToSvnPaths(files), recurse == Recurse.Full); |
||||||
|
} catch (SvnException ex) { |
||||||
|
throw new SvnClientException(ex); |
||||||
|
} finally { |
||||||
|
AfterOperation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void Move(string from, string to, bool force) |
||||||
|
{ |
||||||
|
Debug("SVN: Move(" + from + ", " + to + ", " + force + ")"); |
||||||
|
BeforeOperation(); |
||||||
|
try { |
||||||
|
client.Move3(from, to, force); |
||||||
|
} catch (SvnException ex) { |
||||||
|
throw new SvnClientException(ex); |
||||||
|
} finally { |
||||||
|
AfterOperation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void AddToIgnoreList(string directory, params string[] filesToIgnore) |
||||||
|
{ |
||||||
|
Debug("SVN: AddToIgnoreList(" + directory + ", " + string.Join(",", filesToIgnore) + ")"); |
||||||
|
string propertyValue = GetPropertyValue(directory, "svn:ignore"); |
||||||
|
StringBuilder b = new StringBuilder(); |
||||||
|
if (propertyValue != null) { |
||||||
|
using (StringReader r = new StringReader(propertyValue)) { |
||||||
|
string line; |
||||||
|
while ((line = r.ReadLine()) != null) { |
||||||
|
if (line.Length > 0) { |
||||||
|
b.AppendLine(line); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
foreach (string file in filesToIgnore) |
||||||
|
b.AppendLine(file); |
||||||
|
SetPropertyValue(directory, "svn:ignore", b.ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
public void Log(string[] paths, Revision start, Revision end, |
||||||
|
int limit, bool discoverChangePaths, bool strictNodeHistory, |
||||||
|
Action<LogMessage> logMessageReceiver) |
||||||
|
{ |
||||||
|
Debug("SVN: Log({" + string.Join(",", paths) + "}, " + start + ", " + end + |
||||||
|
", " + limit + ", " + discoverChangePaths + ", " + strictNodeHistory + ")"); |
||||||
|
BeforeOperation(); |
||||||
|
try { |
||||||
|
client.Log2( |
||||||
|
ToSvnPaths(paths), |
||||||
|
start, end, limit, discoverChangePaths, strictNodeHistory, |
||||||
|
delegate (IntPtr baton, AprHash changed_paths, int revision, AprString author, AprString date, AprString message, AprPool pool) { |
||||||
|
Debug("SVN: Log: Got revision " + revision); |
||||||
|
DateTime dateTime = DateTime.MinValue; |
||||||
|
DateTime.TryParse(date.Value, out dateTime); |
||||||
|
LogMessage msg = new LogMessage() { |
||||||
|
Revision = revision, |
||||||
|
Author = author.Value, |
||||||
|
Date = dateTime, |
||||||
|
Message = message.Value |
||||||
|
}; |
||||||
|
if (discoverChangePaths) { |
||||||
|
msg.ChangedPaths = new List<ChangedPath>(); |
||||||
|
foreach (AprHashEntry entry in changed_paths) { |
||||||
|
SvnLogChangedPath changedPath = entry.Value; |
||||||
|
msg.ChangedPaths.Add(new ChangedPath { |
||||||
|
Path = entry.KeyAsString, |
||||||
|
CopyFromPath = changedPath.CopyFromPath.Value, |
||||||
|
CopyFromRevision = changedPath.CopyFromRev, |
||||||
|
Action = changedPath.Action |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
logMessageReceiver(msg); |
||||||
|
return SvnError.NoError; |
||||||
|
}, |
||||||
|
IntPtr.Zero |
||||||
|
); |
||||||
|
Debug("SVN: Log finished"); |
||||||
|
} catch (SvnException ex) { |
||||||
|
throw new SvnClientException(ex); |
||||||
|
} finally { |
||||||
|
AfterOperation(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static StatusKind ToStatusKind(SvnWcStatus.Kind kind) |
||||||
|
{ |
||||||
|
switch (kind) { |
||||||
|
case SvnWcStatus.Kind.Added: |
||||||
|
return StatusKind.Added; |
||||||
|
case SvnWcStatus.Kind.Conflicted: |
||||||
|
return StatusKind.Conflicted; |
||||||
|
case SvnWcStatus.Kind.Deleted: |
||||||
|
return StatusKind.Deleted; |
||||||
|
case SvnWcStatus.Kind.External: |
||||||
|
return StatusKind.External; |
||||||
|
case SvnWcStatus.Kind.Ignored: |
||||||
|
return StatusKind.Ignored; |
||||||
|
case SvnWcStatus.Kind.Incomplete: |
||||||
|
return StatusKind.Incomplete; |
||||||
|
case SvnWcStatus.Kind.Merged: |
||||||
|
return StatusKind.Merged; |
||||||
|
case SvnWcStatus.Kind.Missing: |
||||||
|
return StatusKind.Missing; |
||||||
|
case SvnWcStatus.Kind.Modified: |
||||||
|
return StatusKind.Modified; |
||||||
|
case SvnWcStatus.Kind.Normal: |
||||||
|
return StatusKind.Normal; |
||||||
|
case SvnWcStatus.Kind.Obstructed: |
||||||
|
return StatusKind.Obstructed; |
||||||
|
case SvnWcStatus.Kind.Replaced: |
||||||
|
return StatusKind.Replaced; |
||||||
|
case SvnWcStatus.Kind.Unversioned: |
||||||
|
return StatusKind.Unversioned; |
||||||
|
default: |
||||||
|
return StatusKind.None; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class LogMessage |
||||||
|
{ |
||||||
|
public int Revision; |
||||||
|
public string Author; |
||||||
|
public DateTime Date; |
||||||
|
public string Message; |
||||||
|
|
||||||
|
public List<ChangedPath> ChangedPaths; |
||||||
|
} |
||||||
|
|
||||||
|
public class ChangedPath |
||||||
|
{ |
||||||
|
public string Path; |
||||||
|
public string CopyFromPath; |
||||||
|
public int CopyFromRevision; |
||||||
|
/// <summary>
|
||||||
|
/// change action ('A','D','R' or 'M')
|
||||||
|
/// </summary>
|
||||||
|
public char Action; |
||||||
|
} |
||||||
|
|
||||||
|
public class Revision |
||||||
|
{ |
||||||
|
SvnRevision revision; |
||||||
|
|
||||||
|
public static readonly Revision Base = new SvnRevision(Svn.Revision.Base); |
||||||
|
public static readonly Revision Committed = new SvnRevision(Svn.Revision.Committed); |
||||||
|
public static readonly Revision Head = new SvnRevision(Svn.Revision.Head); |
||||||
|
public static readonly Revision Working = new SvnRevision(Svn.Revision.Working); |
||||||
|
public static readonly Revision Unspecified = new SvnRevision(Svn.Revision.Unspecified); |
||||||
|
|
||||||
|
public static Revision FromNumber(int number) |
||||||
|
{ |
||||||
|
return new SvnRevision(number); |
||||||
|
} |
||||||
|
|
||||||
|
public static implicit operator SvnRevision(Revision r) |
||||||
|
{ |
||||||
|
return r.revision; |
||||||
|
} |
||||||
|
|
||||||
|
public static implicit operator Revision(SvnRevision r) |
||||||
|
{ |
||||||
|
return new Revision() { revision = r }; |
||||||
|
} |
||||||
|
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
switch (revision.Kind) { |
||||||
|
case Svn.Revision.Base: |
||||||
|
return "base"; |
||||||
|
case Svn.Revision.Committed: |
||||||
|
return "committed"; |
||||||
|
case Svn.Revision.Date: |
||||||
|
return AprTime.ToDateTime(revision.Date).ToString(); |
||||||
|
case Svn.Revision.Head: |
||||||
|
return "head"; |
||||||
|
case Svn.Revision.Number: |
||||||
|
return revision.Number.ToString(); |
||||||
|
case Svn.Revision.Previous: |
||||||
|
return "previous"; |
||||||
|
case Svn.Revision.Unspecified: |
||||||
|
return "unspecified"; |
||||||
|
case Svn.Revision.Working: |
||||||
|
return "working"; |
||||||
|
default: |
||||||
|
return "unknown"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public class Status |
||||||
|
{ |
||||||
|
public bool Copied { get; set; } |
||||||
|
public StatusKind TextStatus { get; set; } |
||||||
|
} |
||||||
|
|
||||||
|
public enum Recurse |
||||||
|
{ |
||||||
|
None, |
||||||
|
Full |
||||||
|
} |
||||||
|
|
||||||
|
public class SvnClientException : Exception |
||||||
|
{ |
||||||
|
public readonly int ErrorCode; |
||||||
|
|
||||||
|
internal SvnClientException(SvnException ex) : base(ex.Message, ex) |
||||||
|
{ |
||||||
|
LoggingService.Debug(ex); |
||||||
|
ErrorCode = ex.AprErr; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the inner exception of the exception being wrapped.
|
||||||
|
/// </summary>
|
||||||
|
public Exception GetInnerException() |
||||||
|
{ |
||||||
|
return InnerException.InnerException; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public enum StatusKind |
||||||
|
{ |
||||||
|
None, |
||||||
|
Added, |
||||||
|
Conflicted, |
||||||
|
Deleted, |
||||||
|
Modified, |
||||||
|
Replaced, |
||||||
|
External, |
||||||
|
Ignored, |
||||||
|
Incomplete, |
||||||
|
Merged, |
||||||
|
Missing, |
||||||
|
Obstructed, |
||||||
|
Normal, |
||||||
|
Unversioned |
||||||
|
} |
||||||
|
} |
||||||
@ -1,15 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
||||||
|
|
||||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> |
|
||||||
<description>Updates the assembly version in GlobalAssemblyInfo.cs</description> |
|
||||||
|
|
||||||
<!-- required because Vista otherwise thinks UpdateAssemblyInfo requires admin rights --> |
|
||||||
<!-- because it contains the word "Update" --> |
|
||||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> |
|
||||||
<security> |
|
||||||
<requestedPrivileges> |
|
||||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/> |
|
||||||
</requestedPrivileges> |
|
||||||
</security> |
|
||||||
</trustInfo> |
|
||||||
</assembly> |
|
||||||
@ -0,0 +1,21 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> |
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> |
||||||
|
<security> |
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> |
||||||
|
<!-- |
||||||
|
The presence of the "requestedExecutionLevel" node will disable |
||||||
|
file and registry virtualization on Vista. |
||||||
|
|
||||||
|
Use the "level" attribute to specify the User Account Control level: |
||||||
|
asInvoker = Never prompt for elevation |
||||||
|
requireAdministrator = Always prompt for elevation |
||||||
|
highestAvailable = Prompt for elevation when started by administrator, |
||||||
|
but do not prompt for administrator password when started by |
||||||
|
standard user. |
||||||
|
--> |
||||||
|
<requestedExecutionLevel level="asInvoker"/> |
||||||
|
</requestedPrivileges> |
||||||
|
</security> |
||||||
|
</trustInfo> |
||||||
|
</assembly> |
||||||
Loading…
Reference in new issue