Cleanup error marshaling and generating code #183

Closed
wants to merge 6 commits into
from
@@ -62,26 +62,19 @@ public static void Success(int result, bool allowPositiveResult = false)
return;
}
- string errorMessage;
- GitError error = NativeMethods.giterr_last().MarshalAsGitError();
-
-
+ var error = NativeMethods.giterr_last();
if (error == null)
{
- error = new GitError { Klass = GitErrorType.Unknown, Message = IntPtr.Zero };
- errorMessage = "No error message has been provided by the native library";
- }
- else
- {
- errorMessage = Utf8Marshaler.FromNative(error.Message);
+ throw new LibGit2SharpException(
+ (GitErrorCode)result,
+ GitErrorCategory.Unknown,
+ "No error message has been provided by the native library");
}
throw new LibGit2SharpException(
- String.Format(CultureInfo.InvariantCulture, "An error was raised by libgit2. Class = {0} ({1}).{2}{3}",
- error.Klass,
- result,
- Environment.NewLine,
- errorMessage));
+ (GitErrorCode)result,
+ error.Category,
+ Utf8Marshaler.FromNative(error.Message));
}
/// <summary>
@@ -108,8 +101,8 @@ public static void GitObjectIsNotNull(GitObject gitObject, string identifier)
}
throw new LibGit2SharpException(string.Format(CultureInfo.InvariantCulture,
- "No valid git object identified by '{0}' exists in the repository.",
- identifier));
+ "No valid git object identified by '{0}' exists in the repository.",
+ identifier));
}
}
}
@@ -7,6 +7,6 @@ namespace LibGit2Sharp.Core
internal class GitError
{
public IntPtr Message;
- public GitErrorType Klass;
+ public GitErrorCategory Category;
}
}
@@ -1,6 +1,6 @@
namespace LibGit2Sharp.Core
{
- internal enum GitErrorType
+ public enum GitErrorCategory
{
Unknown = -1,
NoMemory,
@@ -1,6 +1,6 @@
namespace LibGit2Sharp.Core
{
- internal enum GitErrorCode
+ public enum GitErrorCode
{
Ok = 0,
Error = -1,
@@ -0,0 +1,47 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace LibGit2Sharp.Core
+{
+ internal class GitErrorMarshaler : ICustomMarshaler
+ {
+ static readonly GitErrorMarshaler staticInstance = new GitErrorMarshaler();
+
+ public void CleanUpManagedData(object managedObj)
+ {
+ }
+
+ public void CleanUpNativeData(IntPtr pNativeData)
+ {
+ if (pNativeData != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(pNativeData);
+ }
+ }
+
+ public int GetNativeDataSize()
+ {
+ return -1;
+ }
+
+ public IntPtr MarshalManagedToNative(object managedObj)
+ {
+ throw new NotImplementedException();
+ }
+
+ public object MarshalNativeToManaged(IntPtr pNativeData)
+ {
+ return NativeToGitError(pNativeData);
+ }
+
+ protected GitError NativeToGitError(IntPtr pNativeData)
+ {
+ return (GitError)Marshal.PtrToStructure(pNativeData, typeof(GitError));
+ }
+
+ public static ICustomMarshaler GetInstance(string cookie)
+ {
+ return staticInstance;
+ }
+ }
+}
@@ -1,12 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace LibGit2Sharp.Core.Handles
-{
- internal class GitErrorSafeHandle : NotOwnedSafeHandleBase
- {
- public GitError MarshalAsGitError()
- {
- return (GitError)Marshal.PtrToStructure(handle, typeof(GitError));
- }
- }
-}
@@ -65,7 +65,8 @@ public static bool RepositoryStateChecker(RepositorySafeHandle repositoryPtr, Fu
}
[DllImport(libgit2)]
- public static extern GitErrorSafeHandle giterr_last();
+ [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(GitErrorMarshaler))]
+ public static extern GitError giterr_last();
[DllImport(libgit2)]
public static extern int git_blob_create_fromdisk(
@@ -78,10 +78,10 @@
<Compile Include="Core\GitDiff.cs" />
<Compile Include="Core\GitDiffExtensions.cs" />
<Compile Include="Core\GitError.cs" />
- <Compile Include="Core\GitErrorType.cs" />
+ <Compile Include="Core\GitErrorCategory.cs" />
+ <Compile Include="Core\GitErrorMarshaler.cs" />
<Compile Include="Core\GitNoteData.cs" />
<Compile Include="Core\GitObjectExtensions.cs" />
- <Compile Include="Core\Handles\GitErrorSafeHandle.cs" />
<Compile Include="Core\Handles\NoteSafeHandle.cs" />
<Compile Include="Core\Handles\ObjectDatabaseSafeHandle.cs" />
<Compile Include="Core\Handles\DiffListSafeHandle.cs" />
@@ -1,5 +1,6 @@
using System;
-using System.Runtime.Serialization;
+using System.Globalization;
+using LibGit2Sharp.Core;
namespace LibGit2Sharp
{
@@ -39,9 +40,12 @@ public LibGit2Exception(string message, Exception innerException)
/// <summary>
/// The exception that is thrown when an error occurs during application execution.
/// </summary>
- [Serializable]
public class LibGit2SharpException : Exception
{
+ readonly GitErrorCode code;
+ readonly GitErrorCategory category;
+ readonly bool isLibraryError;
+
/// <summary>
/// Initializes a new instance of the <see cref = "LibGit2SharpException" /> class.
/// </summary>
@@ -50,6 +54,16 @@ public LibGit2SharpException()
}
/// <summary>
+ /// Initializes a new instance of the <see cref = "LibGit2SharpException" /> class.
+ /// </summary>
+ public LibGit2SharpException(GitErrorCode code, GitErrorCategory category, string message) : base(message)
+ {
+ Data["libgit2.code"] = this.code = code;
+ Data["libgit2.class"] = this.category = category;
+ isLibraryError = true;
+ }
+
+ /// <summary>
/// Initializes a new instance of the <see cref = "LibGit2SharpException" /> class with a specified error message.
/// </summary>
/// <param name = "message">A message that describes the error. </param>
@@ -69,13 +83,30 @@ public LibGit2SharpException(string message, Exception innerException)
}
/// <summary>
- /// Initializes a new instance of the <see cref = "LibGit2SharpException" /> class with a serialized data.
+ /// The specific libgit2 error code.
/// </summary>
- /// <param name = "info">The <see cref="SerializationInfo "/> that holds the serialized object data about the exception being thrown.</param>
- /// <param name = "context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
- protected LibGit2SharpException(SerializationInfo info, StreamingContext context)
- : base(info, context)
+ public GitErrorCode Code
@nulltoken
nulltoken Jun 22, 2012 Member

@tclem @Haacked As previously discussed, I'm really not willing to make the GitErrorCode and GitErrorCategory types publicly exposed, nor to expose such properties. Indeed, I don't feel the grain is fine enough (yet?) to safely build a stable/long lasting error handling strategy.

Therefore, for now, I'd prefer to only expose int typed values in the Data dictionary.
This makes the libgit2 native error codes available for logging purpose.

In order to reduce the pain, we'll indeed have to add proper exceptions to LibGit2Sharp. Which one would you see fit?

@nulltoken
nulltoken Jun 22, 2012 Member

@tclem @Haacked I've created #189 to cope with the lack of proper exceptions issue

+ {
+ get { return Data.Contains("libgit2.code") ? (GitErrorCode)Data["libgit2.code"] : GitErrorCode.Error; }
+ }
+
+ /// <summary>
+ /// The specific libgit2 error class.
+ /// </summary>
+ public GitErrorCategory Category
+ {
+ get { return Data.Contains("libgit2.class") ? (GitErrorCategory)Data["libgit2.class"] : GitErrorCategory.Unknown; }
+ }
+
+ public override string ToString()
{
+ return isLibraryError
+ ? String.Format(CultureInfo.InvariantCulture, "An error was raised by libgit2. Class = {0} ({1}).{2}{3}",
+ category,
+ code,
+ Environment.NewLine,
+ Message)
+ : base.ToString();
}
}
}