Checkpoint
This commit is contained in:
@@ -7,4 +7,8 @@
|
||||
<RootNamespace>Foodsoft.Alpm</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace Foodsoft.Alpm
|
||||
{
|
||||
public AlpmException() { }
|
||||
internal AlpmException(SafeAlpmHandle handle) : base(alpm.alpm_strerror(alpm.alpm_errno(handle))) { }
|
||||
public AlpmException(Error errno) : base(alpm.alpm_strerror(errno)) { }
|
||||
public AlpmException(Error errno, Exception inner) : base(alpm.alpm_strerror(errno), inner) { }
|
||||
public AlpmException(ErrorCode errno) : base(alpm.alpm_strerror(errno)) { }
|
||||
public AlpmException(ErrorCode errno, Exception inner) : base(alpm.alpm_strerror(errno), inner) { }
|
||||
|
||||
protected AlpmException(SerializationInfo info,
|
||||
StreamingContext context) : base(info, context) { }
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Foodsoft.Alpm
|
||||
public readonly struct Backup : IEquatable<Backup>
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Hash { get; }
|
||||
public string? Hash { get; }
|
||||
|
||||
public bool Equals(Backup other)
|
||||
{
|
||||
@@ -24,17 +24,17 @@ namespace Foodsoft.Alpm
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private readonly unsafe struct NativeBackup
|
||||
private readonly struct NativeBackup
|
||||
{
|
||||
internal readonly sbyte* name;
|
||||
internal readonly sbyte* hash;
|
||||
internal readonly IntPtr name;
|
||||
internal readonly IntPtr hash;
|
||||
}
|
||||
|
||||
internal unsafe Backup(IntPtr ptr)
|
||||
{
|
||||
var native = (NativeBackup*) ptr;
|
||||
Name = new string(native->name);
|
||||
Hash = new string(native->hash);
|
||||
Name = Marshal.PtrToStringUTF8(native->name)!;
|
||||
Hash = Marshal.PtrToStringUTF8(native->hash)!;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace Foodsoft.Alpm
|
||||
var ret = alpm.alpm_pkg_checkmd5sum(Handle);
|
||||
if (ret == 0) return true;
|
||||
var errno = alpm.alpm_errno(Handle.SafeAlpmHandle);
|
||||
return errno == Error.PkgInvalid ? false : throw new AlpmException(errno);
|
||||
return errno == ErrorCode.PkgInvalid ? false : throw new AlpmException(errno);
|
||||
}
|
||||
|
||||
public void SetInstallReason(InstallReason reason)
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Foodsoft.Alpm
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (var s in value)
|
||||
if (alpm.alpm_list_append_strdup(ref listPtr, s) == IntPtr.Zero)
|
||||
throw new AlpmException(Error.Memory);
|
||||
throw new AlpmException(ErrorCode.Memory);
|
||||
|
||||
success = true;
|
||||
}
|
||||
@@ -63,8 +63,8 @@ namespace Foodsoft.Alpm
|
||||
|
||||
public SigLevel SigLevel => alpm.alpm_db_get_siglevel(_handle);
|
||||
|
||||
public Error Valid =>
|
||||
alpm.alpm_db_get_valid(_handle) != 0 ? alpm.alpm_errno(_handle.SafeAlpmHandle) : Error.OK;
|
||||
public ErrorCode Valid =>
|
||||
alpm.alpm_db_get_valid(_handle) != 0 ? alpm.alpm_errno(_handle.SafeAlpmHandle) : ErrorCode.OK;
|
||||
|
||||
public CachePackageList PackageCache
|
||||
{
|
||||
@@ -118,7 +118,7 @@ namespace Foodsoft.Alpm
|
||||
if (pkgPtr == IntPtr.Zero)
|
||||
{
|
||||
var err = alpm.alpm_errno(_handle.SafeAlpmHandle);
|
||||
if (err == Error.PkgNotFound)
|
||||
if (err == ErrorCode.PkgNotFound)
|
||||
return null;
|
||||
throw new AlpmException(err);
|
||||
}
|
||||
@@ -134,7 +134,7 @@ namespace Foodsoft.Alpm
|
||||
if (result == IntPtr.Zero)
|
||||
{
|
||||
var errNo = alpm.alpm_errno(_handle.SafeAlpmHandle);
|
||||
if (errNo != Error.OK)
|
||||
if (errNo != ErrorCode.OK)
|
||||
throw new AlpmException(errNo);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,22 +5,12 @@ namespace Foodsoft.Alpm
|
||||
{
|
||||
public class Depend : IEquatable<Depend>
|
||||
{
|
||||
public enum ModType
|
||||
{
|
||||
Any = 1,
|
||||
Equal,
|
||||
GreaterThanOrEqual,
|
||||
LessThanOrEqual,
|
||||
GreaterThan,
|
||||
LessThan
|
||||
}
|
||||
|
||||
internal unsafe Depend(IntPtr ptr)
|
||||
{
|
||||
var native = (NativeDepend*) ptr;
|
||||
Name = new string(native->name);
|
||||
Version = new string(native->version);
|
||||
Description = new string(native->description);
|
||||
Name = Marshal.PtrToStringUTF8(native->name)!;
|
||||
Version = Marshal.PtrToStringUTF8(native->version)!;
|
||||
Description = Marshal.PtrToStringUTF8(native->description)!;
|
||||
NameHash = native->name_hash;
|
||||
Mod = native->mod;
|
||||
}
|
||||
@@ -48,13 +38,23 @@ namespace Foodsoft.Alpm
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private readonly unsafe struct NativeDepend
|
||||
private readonly struct NativeDepend
|
||||
{
|
||||
internal readonly sbyte* name;
|
||||
internal readonly sbyte* version;
|
||||
internal readonly sbyte* description;
|
||||
internal readonly IntPtr name;
|
||||
internal readonly IntPtr version;
|
||||
internal readonly IntPtr description;
|
||||
internal readonly ulong name_hash;
|
||||
internal readonly ModType mod;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ModType
|
||||
{
|
||||
Any = 1,
|
||||
Equal,
|
||||
GreaterThanOrEqual,
|
||||
LessThanOrEqual,
|
||||
GreaterThan,
|
||||
LessThan
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ namespace Foodsoft.Alpm
|
||||
Encoding.UTF8.GetBytes(pSrc, s.Length, pDest, poolBuffer.Length - start);
|
||||
pDest[nbWritten] = 0;
|
||||
if (alpm.alpm_list_append(ref listPtr, (IntPtr) pDest) == IntPtr.Zero)
|
||||
throw new AlpmException(Error.Memory);
|
||||
throw new AlpmException(ErrorCode.Memory);
|
||||
start += nbWritten + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Foodsoft.Alpm
|
||||
{
|
||||
public enum Error
|
||||
public enum ErrorCode
|
||||
{
|
||||
OK = 0,
|
||||
Memory,
|
||||
@@ -80,28 +78,4 @@ namespace Foodsoft.Alpm
|
||||
/*MissingCompileTimeFeatures*/
|
||||
MissingCapabilitySignatures
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum LogLevel
|
||||
{
|
||||
Error = 1,
|
||||
Warning = (1 << 1),
|
||||
Debug = (1 << 2),
|
||||
Function = (1 << 3)
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum SigLevel
|
||||
{
|
||||
Package = (1 << 0),
|
||||
PackageOptional = (1 << 1),
|
||||
PackageMarginalOK = (1 << 2),
|
||||
PackageUnknownOK = (1 << 3),
|
||||
|
||||
Database = (1 << 10),
|
||||
DatabaseOptional = (1 << 11),
|
||||
DatabaseMarginalOK = (1 << 12),
|
||||
DatabaseUnknownOK = (1 << 13),
|
||||
UseDefault = (1 << 31)
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace Foodsoft.Alpm
|
||||
|
||||
refs[pkgPtr] = pkg;
|
||||
if (alpm.alpm_list_append(ref listPtr, handle.DangerousGetHandle()) == IntPtr.Zero)
|
||||
throw new AlpmException(Error.Memory);
|
||||
throw new AlpmException(ErrorCode.Memory);
|
||||
}
|
||||
|
||||
var foundPtr = alpm.alpm_find_satisfier(listPtr, depString);
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Foodsoft.Alpm.Interop;
|
||||
|
||||
namespace Foodsoft.Alpm
|
||||
{
|
||||
public sealed class Handle : IDisposable
|
||||
{
|
||||
private readonly object _eventLock = new object();
|
||||
private readonly SafeAlpmHandle _handle;
|
||||
|
||||
public Handle(string root, string dbpath)
|
||||
private EventHandler<LogEventArgs> _logEvent;
|
||||
|
||||
public Handle(string root, string dbPath)
|
||||
{
|
||||
_handle = alpm.alpm_initialize(root, dbpath, out var err);
|
||||
_handle = alpm.alpm_initialize(root, dbPath, out var err);
|
||||
if (_handle.IsInvalid) throw new AlpmException(err);
|
||||
}
|
||||
|
||||
@@ -22,6 +26,8 @@ namespace Foodsoft.Alpm
|
||||
set => Detail.SetStringCollection(value, _handle, s => alpm.alpm_option_add_cachedir(_handle, s));
|
||||
}
|
||||
|
||||
public LogLevel LogLevel { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_handle.Dispose();
|
||||
@@ -55,5 +61,42 @@ namespace Foodsoft.Alpm
|
||||
{
|
||||
return alpm.alpm_pkg_should_ignore(_handle, pkg.Handle) == 0;
|
||||
}
|
||||
|
||||
public event EventHandler<LogEventArgs> Log
|
||||
{
|
||||
add
|
||||
{
|
||||
void LogCallback(LogLevel level, IntPtr format, IntPtr args)
|
||||
{
|
||||
if (level > LogLevel) return;
|
||||
_logEvent?.Invoke(this,
|
||||
new LogEventArgs {Level = level, Message = CFormatter.Format(format, args)});
|
||||
}
|
||||
|
||||
lock (_eventLock)
|
||||
{
|
||||
var wasEmpty = _logEvent == null;
|
||||
_logEvent += value;
|
||||
if (wasEmpty)
|
||||
alpm.alpm_option_set_logcb(_handle, LogCallback);
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
lock (_eventLock)
|
||||
{
|
||||
// ReSharper disable once DelegateSubtraction
|
||||
_logEvent -= value;
|
||||
if (_logEvent == null)
|
||||
alpm.alpm_option_set_logcb(_handle, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct LogEventArgs
|
||||
{
|
||||
public LogLevel Level;
|
||||
public string Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Alpm/Interop/CFormatter.cs
Normal file
88
Alpm/Interop/CFormatter.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Foodsoft.Alpm.Interop
|
||||
{
|
||||
internal static class CFormatter
|
||||
{
|
||||
private static readonly int vaListCopyNWords;
|
||||
|
||||
private static readonly Vsnprintf? vsnprintfFunc;
|
||||
|
||||
static CFormatter()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ||
|
||||
RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
|
||||
{
|
||||
vaListCopyNWords = RuntimeInformation.ProcessArchitecture switch
|
||||
{
|
||||
Architecture.X86 => 1,
|
||||
Architecture.X64 => 3,
|
||||
Architecture.Arm => 1,
|
||||
Architecture.Arm64 => 4,
|
||||
_ => vaListCopyNWords
|
||||
};
|
||||
vsnprintfFunc = vsnprintfLibc;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
vaListCopyNWords = 1;
|
||||
vsnprintfFunc = vsnprintfUCrt;
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
vaListCopyNWords = RuntimeInformation.ProcessArchitecture switch
|
||||
{
|
||||
Architecture.X86 => 1,
|
||||
Architecture.X64 => 3,
|
||||
Architecture.Arm => 1,
|
||||
Architecture.Arm64 => 1,
|
||||
_ => vaListCopyNWords
|
||||
};
|
||||
vsnprintfFunc = vsnprintfLibc;
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe string Format(IntPtr format, IntPtr vaList)
|
||||
{
|
||||
const int bufSize = 256;
|
||||
if (vsnprintfFunc == null || vaListCopyNWords <= 0)
|
||||
return "[Formatter unsupported for platform]";
|
||||
|
||||
var vaListBuf = (void**) vaList;
|
||||
var vaListCopy = stackalloc void*[vaListCopyNWords];
|
||||
for (var i = 0; i < vaListCopyNWords; i++) vaListCopy[i] = vaListBuf[i];
|
||||
|
||||
var strBuf = stackalloc byte[bufSize];
|
||||
var strBufPtr = (IntPtr) strBuf;
|
||||
|
||||
var nbNeed = vsnprintfFunc(strBufPtr, (UIntPtr) bufSize, format, vaList);
|
||||
|
||||
if (nbNeed < bufSize)
|
||||
return Marshal.PtrToStringUTF8(strBufPtr, nbNeed);
|
||||
|
||||
var pool = ArrayPool<byte>.Shared;
|
||||
|
||||
var buffer = pool.Rent(nbNeed + 1);
|
||||
fixed (byte* pb = buffer)
|
||||
{
|
||||
nbNeed = vsnprintfFunc((IntPtr) pb, (UIntPtr) buffer.Length, format, (IntPtr) vaListCopy);
|
||||
}
|
||||
|
||||
var result = Encoding.UTF8.GetString(buffer, 0, nbNeed);
|
||||
pool.Return(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
private delegate int Vsnprintf(IntPtr buffer, UIntPtr size, IntPtr format, IntPtr args);
|
||||
|
||||
|
||||
[DllImport("libc", EntryPoint = "vsnprintf", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern int vsnprintfLibc(IntPtr buffer, UIntPtr size, IntPtr format, IntPtr args);
|
||||
|
||||
[DllImport("ucrt", EntryPoint = "vsnprintf", CallingConvention = CallingConvention.Cdecl)]
|
||||
internal static extern int vsnprintfUCrt(IntPtr buffer, UIntPtr size, IntPtr format, IntPtr args);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Foodsoft.Alpm.Marshalling
|
||||
{
|
||||
@@ -30,9 +32,8 @@ namespace Foodsoft.Alpm.Marshalling
|
||||
{
|
||||
return Marshal.PtrToStringUTF8(pNativeData)!;
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
// ReSharper disable once UnusedParameter.Local
|
||||
|
||||
[UsedImplicitly]
|
||||
private static ICustomMarshaler GetInstance(string cookie)
|
||||
{
|
||||
return _instance;
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Foodsoft.Alpm.Marshalling
|
||||
{
|
||||
@@ -7,8 +8,7 @@ namespace Foodsoft.Alpm.Marshalling
|
||||
{
|
||||
private static readonly UTF8Return _instance = default;
|
||||
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
// ReSharper disable once UnusedParameter.Local
|
||||
[UsedImplicitly]
|
||||
private static ICustomMarshaler GetInstance(string cookie)
|
||||
{
|
||||
return _instance;
|
||||
13
Alpm/LogLevel.cs
Normal file
13
Alpm/LogLevel.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Foodsoft.Alpm
|
||||
{
|
||||
[Flags]
|
||||
public enum LogLevel
|
||||
{
|
||||
Error = 1,
|
||||
Warning = (1 << 1),
|
||||
Debug = (1 << 2),
|
||||
Function = (1 << 3)
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,7 @@ namespace Foodsoft.Alpm
|
||||
{
|
||||
public abstract class Package : IPackageData
|
||||
{
|
||||
internal Package(SafePackageHandle handle)
|
||||
{
|
||||
Handle = handle;
|
||||
}
|
||||
internal Package(SafePackageHandle handle) => Handle = handle;
|
||||
|
||||
internal SafePackageHandle Handle { get; }
|
||||
|
||||
@@ -57,24 +54,15 @@ namespace Foodsoft.Alpm
|
||||
|
||||
public virtual Database? DB => null;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Handle.Dispose();
|
||||
}
|
||||
public void Dispose() => Handle.Dispose();
|
||||
|
||||
public IEnumerable<Package> ComputeRequiredBy()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public IEnumerable<Package> ComputeRequiredBy() => throw new NotImplementedException();
|
||||
|
||||
public IEnumerable<Package> ComputeOptionalFor()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static int VersionCompare(string v1, string v2)
|
||||
{
|
||||
return alpm.alpm_pkg_vercmp(v1, v2);
|
||||
}
|
||||
public static int VersionCompare(string v1, string v2) => alpm.alpm_pkg_vercmp(v1, v2);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Runtime.ConstrainedExecution;
|
||||
|
||||
namespace Foodsoft.Alpm
|
||||
{
|
||||
internal class SafeFilePackageHandle : SafePackageHandle
|
||||
internal sealed class SafeFilePackageHandle : SafePackageHandle
|
||||
{
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
[PrePrepareMethod]
|
||||
|
||||
19
Alpm/SigLevel.cs
Normal file
19
Alpm/SigLevel.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Foodsoft.Alpm
|
||||
{
|
||||
[Flags]
|
||||
public enum SigLevel
|
||||
{
|
||||
Package = (1 << 0),
|
||||
PackageOptional = (1 << 1),
|
||||
PackageMarginalOK = (1 << 2),
|
||||
PackageUnknownOK = (1 << 3),
|
||||
|
||||
Database = (1 << 10),
|
||||
DatabaseOptional = (1 << 11),
|
||||
DatabaseMarginalOK = (1 << 12),
|
||||
DatabaseUnknownOK = (1 << 13),
|
||||
UseDefault = (1 << 31)
|
||||
}
|
||||
}
|
||||
13
Alpm/alpm.cs
13
Alpm/alpm.cs
@@ -16,7 +16,6 @@ namespace Foodsoft.Alpm
|
||||
// ReSharper disable once InconsistentNaming
|
||||
internal static class alpm
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public delegate void alpm_fn_free(IntPtr ptr);
|
||||
|
||||
[DllImport(nameof(alpm))]
|
||||
@@ -145,6 +144,12 @@ namespace Foodsoft.Alpm
|
||||
[DllImport(nameof(alpm))]
|
||||
public static extern int alpm_pkg_free(IntPtr ptr);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void LogFuncCallBack(LogLevel level, IntPtr format, IntPtr argsAddress);
|
||||
|
||||
[DllImport(nameof(alpm))]
|
||||
public static extern IntPtr alpm_option_set_logcb(SafeAlpmHandle handle, LogFuncCallBack? cb);
|
||||
|
||||
[DllImport(nameof(alpm))]
|
||||
public static extern IntPtr alpm_option_get_cachedirs(SafeAlpmHandle handle);
|
||||
|
||||
@@ -159,11 +164,11 @@ namespace Foodsoft.Alpm
|
||||
string cachedir);
|
||||
|
||||
[DllImport(nameof(alpm))]
|
||||
public static extern Error alpm_errno(SafeAlpmHandle handle);
|
||||
public static extern ErrorCode alpm_errno(SafeAlpmHandle handle);
|
||||
|
||||
[DllImport(nameof(alpm))]
|
||||
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Return))]
|
||||
public static extern string alpm_strerror(Error err);
|
||||
public static extern string alpm_strerror(ErrorCode err);
|
||||
|
||||
[DllImport(nameof(alpm))]
|
||||
public static extern IntPtr alpm_get_localdb(SafeAlpmHandle handle);
|
||||
@@ -218,7 +223,7 @@ namespace Foodsoft.Alpm
|
||||
public static extern SafeAlpmHandle alpm_initialize(
|
||||
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8In))]
|
||||
string root, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8In))]
|
||||
string dbpath, out Error err);
|
||||
string dbpath, out ErrorCode err);
|
||||
|
||||
[DllImport(nameof(alpm))]
|
||||
public static extern int alpm_release(IntPtr handle);
|
||||
|
||||
Reference in New Issue
Block a user