From 19a9fc06badbd0930067172b8af673b60dd10027 Mon Sep 17 00:00:00 2001 From: "John K. Luebs" Date: Wed, 29 Apr 2020 23:47:06 -0400 Subject: [PATCH] checkpoint --- .idea/.idea.DotNetAlpm/riderModule.iml | 4 + Alpm.Tests/AlpmIntegrationTest.cs | 32 ++++++ Alpm/API.cs | 4 +- Alpm/Alpm.csproj | 1 - Alpm/AlpmException.cs | 18 ++++ Alpm/CachePackage.cs | 2 +- Alpm/CollectionWrapper`2.cs | 131 ------------------------- Alpm/Database.cs | 75 ++++++++------ Alpm/EnumerableWrapperEx.cs | 123 +++++++++++++++++++++++ Alpm/EnumerableWrapper`3.cs | 82 +++++++++++++++- Alpm/Enums.cs | 19 ++++ Alpm/Exception.cs | 18 ---- Alpm/FilePackage.cs | 11 +++ Alpm/Handle.cs | 44 +++------ Alpm/IAlpmItemsAccessor`1.cs | 15 --- Alpm/IItemsReader`2.cs | 4 +- Alpm/IPackageData.cs | 18 ++-- Alpm/Junk.cs | 13 --- Alpm/Package.cs | 32 +++--- Alpm/PackageList.cs | 74 +++++++++++--- Alpm/SafeCachePackageHandle.cs | 28 +++--- Alpm/SafeDatabaseHandle.cs | 8 +- Alpm/SafeFilePackageHandle.cs | 39 ++++++++ Alpm/SafePackageHandle.cs | 6 +- Alpm/UTF8InMarshaler.cs | 22 +---- Alpm/Wrapper.cs | 36 +++++++ Alpm/alpm.cs | 51 +++++++--- DotNetAlpm.sln | 6 ++ DotNetAlpm.sln.DotSettings | 9 +- Samples/Program.cs | 112 ++++++++++++++++----- Samples/Samples.csproj | 1 + 31 files changed, 678 insertions(+), 360 deletions(-) create mode 100644 Alpm.Tests/AlpmIntegrationTest.cs create mode 100644 Alpm/AlpmException.cs delete mode 100644 Alpm/CollectionWrapper`2.cs create mode 100644 Alpm/EnumerableWrapperEx.cs create mode 100644 Alpm/Enums.cs delete mode 100644 Alpm/Exception.cs create mode 100644 Alpm/FilePackage.cs delete mode 100644 Alpm/IAlpmItemsAccessor`1.cs create mode 100644 Alpm/SafeFilePackageHandle.cs diff --git a/.idea/.idea.DotNetAlpm/riderModule.iml b/.idea/.idea.DotNetAlpm/riderModule.iml index 1a4e0d9..fd05418 100644 --- a/.idea/.idea.DotNetAlpm/riderModule.iml +++ b/.idea/.idea.DotNetAlpm/riderModule.iml @@ -1,6 +1,10 @@ + + + + diff --git a/Alpm.Tests/AlpmIntegrationTest.cs b/Alpm.Tests/AlpmIntegrationTest.cs new file mode 100644 index 0000000..b57c278 --- /dev/null +++ b/Alpm.Tests/AlpmIntegrationTest.cs @@ -0,0 +1,32 @@ +using System; +using System.Linq; +using Foodsoft.Alpm; +using Xunit; + +namespace Alpm.Tests +{ + public class AlpmIntegrationTest : IDisposable + { + private readonly Handle _handle = new Handle("/", "/var/lib/pacman"); + + [Fact] + public void TestLocalDB() + { + using var localDB = _handle.LocalDB; + Assert.Equal(15, localDB.PackageCache.Count()); + } + + [Fact] + public void VersionCompareTest() + { + Assert.True(Package.VersionCompare("1.0-2", "2.0-1") < 0); + Assert.True(Package.VersionCompare("1:1.0-2", "2.0-1") > 0); + Assert.Equal(0, Package.VersionCompare("2.0.2-2", "2.0.2-2")); + } + + public void Dispose() + { + _handle?.Dispose(); + } + } +} \ No newline at end of file diff --git a/Alpm/API.cs b/Alpm/API.cs index 1d1cb3b..ec9b2af 100644 --- a/Alpm/API.cs +++ b/Alpm/API.cs @@ -11,7 +11,7 @@ namespace Foodsoft.Alpm var err = f(); if (err != 0) { - throw new Exception(alpm.alpm_errno(h)); + throw new AlpmException(h); } } @@ -24,7 +24,7 @@ namespace Foodsoft.Alpm var err = f(); if (err < 0) { - throw new Exception(alpm.alpm_errno(h)); + throw new AlpmException(h); } return err == 0; } diff --git a/Alpm/Alpm.csproj b/Alpm/Alpm.csproj index b84ea79..7d9d041 100644 --- a/Alpm/Alpm.csproj +++ b/Alpm/Alpm.csproj @@ -1,7 +1,6 @@ - Module netcoreapp3.1 true enable diff --git a/Alpm/AlpmException.cs b/Alpm/AlpmException.cs new file mode 100644 index 0000000..ab0cc03 --- /dev/null +++ b/Alpm/AlpmException.cs @@ -0,0 +1,18 @@ +using System; +using System.Runtime.Serialization; +using Foodsoft.Alpm; + +namespace Foodsoft.Alpm +{ + [Serializable()] + public class AlpmException : System.Exception + { + public AlpmException() { } + internal AlpmException(SafeAlpmHandle handle) : base(alpm.alpm_strerror(alpm.alpm_errno(handle))) { } + public AlpmException(ErrNo errno) : base(alpm.alpm_strerror(errno)) { } + public AlpmException(ErrNo errno, System.Exception inner) : base(alpm.alpm_strerror(errno), inner) { } + + protected AlpmException(SerializationInfo info, + StreamingContext context) : base(info, context) { } + } +} \ No newline at end of file diff --git a/Alpm/CachePackage.cs b/Alpm/CachePackage.cs index ebed529..a4468bc 100644 --- a/Alpm/CachePackage.cs +++ b/Alpm/CachePackage.cs @@ -13,7 +13,7 @@ namespace Foodsoft.Alpm public void SetInstallReason(InstallReason reason) { if (alpm.alpm_pkg_set_reason(Handle, reason) != 0) - throw new Exception(alpm.alpm_errno(((SafeCachePackageHandle) Handle).SafeAlpmHandle)); + throw new AlpmException(((SafeCachePackageHandle) Handle).SafeAlpmHandle); } } } \ No newline at end of file diff --git a/Alpm/CollectionWrapper`2.cs b/Alpm/CollectionWrapper`2.cs deleted file mode 100644 index a62b87f..0000000 --- a/Alpm/CollectionWrapper`2.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -// FIXME: This is increasing the ref-count on AlpmHandle all the time, so this is NOT correct for database handles, -// or other handles that have a dispose that is not a no-op. -namespace Foodsoft.Alpm -{ - internal class CollectionWrapper : ICollection where TImpl : struct, - IItemsAccessor - { - private TImpl _impl; - - public CollectionWrapper(TImpl impl) - { - _impl = impl; - } - - private static unsafe IntPtr ListNext(IntPtr list) => ((alpm_list_t*) list)->next; - private static unsafe IntPtr ListData(IntPtr list) => ((alpm_list_t*) list)->data; - public IEnumerator GetEnumerator() - { - var safeAlpmHandle = _impl.SafeAlpmHandle; - var release = false; - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - safeAlpmHandle.DangerousAddRef(ref release); - if (!release) throw new ObjectDisposedException(_impl.GetType().FullName); - for (var list = _impl.GetItems(); list != IntPtr.Zero; list = ListNext(list)) - { - yield return _impl.PtrToItem(ListData(list)); - } - } - finally - { - if (release) - safeAlpmHandle.DangerousRelease(); - } - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - public void Add(TElement item) - { - _impl.AddItem(item); - } - - public void Clear() - { - _impl.SetItems(IntPtr.Zero); - } - - - public bool Contains(TElement item) - { - var safeAlpmHandle = _impl.SafeAlpmHandle; - var release = false; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - safeAlpmHandle.DangerousAddRef(ref release); - return _impl.FindItem(item) != IntPtr.Zero; - } - finally - { - if (release) - safeAlpmHandle.DangerousRelease(); - } - } - - public void CopyTo(TElement[] array, int arrayIndex) - { - var safeAlpmHandle = _impl.SafeAlpmHandle; - var release = false; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - safeAlpmHandle.DangerousAddRef(ref release); - var intPtr = _impl.GetItems(); - unsafe - { - for (var list = (alpm_list_t*) intPtr; list != null; list = alpm.alpm_list_next(list)) - { - array[arrayIndex++] = _impl.PtrToItem(list->data); - } - } - } - finally - { - if (release) - safeAlpmHandle.DangerousRelease(); - } - } - - public bool Remove(TElement item) - { - var err = _impl.RemoveItem(item); - if (err < 0) - { - throw new Exception(alpm.alpm_errno(_impl.SafeAlpmHandle)); - } - - return err == 0; - } - - public int Count - { - get - { - var safeAlpmHandle = _impl.SafeAlpmHandle; - var release = false; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - safeAlpmHandle.DangerousAddRef(ref release); - return (int) alpm.alpm_list_count(_impl.GetItems()); - } - finally - { - if (release) - safeAlpmHandle.DangerousRelease(); - } - } - } - - public bool IsReadOnly => false; - } -} \ No newline at end of file diff --git a/Alpm/Database.cs b/Alpm/Database.cs index 033aff1..567379f 100644 --- a/Alpm/Database.cs +++ b/Alpm/Database.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Foodsoft.Alpm @@ -10,44 +11,54 @@ namespace Foodsoft.Alpm internal Database(SafeDatabaseHandle handle) => _handle = handle; - public void Unregister() + public void Unregister() => _handle.Close(); + + public void AddServer(string url) => + API.WrapError(_handle.SafeAlpmHandle, () => alpm.alpm_db_add_server(_handle, url)); + + public bool RemoveServer(string url) => + API.WrapErrorBool(_handle.SafeAlpmHandle, () => alpm.alpm_db_remove_server(_handle, url)); + + private readonly struct ServersImpl : ICollectionImpl { - try - { - API.WrapError(_handle.SafeAlpmHandle, () => alpm.alpm_db_unregister(_handle)); - } - finally - { - _handle.Close(); - } - } - - - private readonly struct ServersAccessor : IItemsReader - { - internal ServersAccessor(SafeDatabaseHandle handle) - { - Handle = handle; - } - - public SafeDatabaseHandle Handle { get; } - public IntPtr GetItems() => alpm.alpm_db_get_servers(Handle); + private readonly SafeDatabaseHandle _handle; + internal ServersImpl(SafeDatabaseHandle handle) => _handle = handle; + public SafeHandle Handle => _handle; + public IntPtr GetItems() => alpm.alpm_db_get_servers(_handle); public string PtrToItem(IntPtr p) => Marshal.PtrToStringUTF8(p)!; } - public void AddServer(string url) => API.WrapError(_handle.SafeAlpmHandle, () => alpm.alpm_db_add_server(_handle, url)); - - public bool RemoveServer(string url) => API.WrapErrorBool(_handle.SafeAlpmHandle, () => alpm.alpm_db_remove_server(_handle, url)); - + // FIXME: This is "bug correct", but probably dumb to do it this way, instead just call add_server + // like all the stuff in handle. public IEnumerable Servers { - get => new EnumerableWrapper(new ServersAccessor(_handle)); + get => EnumerableWrapper.Create(new ServersImpl(_handle)); set { - foreach (var s in value) + var listPtr = IntPtr.Zero; + var success = false; + var err = 0; + RuntimeHelpers.PrepareConstrainedRegions(); + try { - API.WrapError(_handle.SafeAlpmHandle, () => alpm.alpm_db_add_server(_handle, s)); + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var s in value) + { + if (alpm.alpm_list_append_strdup(ref listPtr, s) == IntPtr.Zero) + throw new AlpmException(ErrNo.ERR_MEMORY); + } + success = true; } + finally + { + if (success) + err = alpm.alpm_db_set_servers(_handle, listPtr); + else + alpm.alpm_list_free(listPtr); + } + + if (err != 0) + throw new AlpmException(_handle.SafeAlpmHandle); } } @@ -63,7 +74,7 @@ namespace Foodsoft.Alpm var err = alpm.alpm_db_update(force ? 1 : 0, _handle); if (err < 0) { - throw new Exception(_handle.SafeAlpmHandle); + throw new AlpmException(_handle.SafeAlpmHandle); } return err == 0; @@ -77,7 +88,7 @@ namespace Foodsoft.Alpm var err = alpm.alpm_errno(_handle.SafeAlpmHandle); if (err == ErrNo.ERR_PKG_NOT_FOUND) return null; - throw new Exception(err); + throw new AlpmException(err); } return new CachePackage(new SafeCachePackageHandle(pkgPtr, _handle), this); @@ -89,8 +100,8 @@ namespace Foodsoft.Alpm { var listPtr = alpm.alpm_db_get_pkgcache(_handle); if (listPtr == IntPtr.Zero) - throw new Exception(alpm.alpm_errno(_handle.SafeAlpmHandle)); - return new PackageList(new SafeListHandle(listPtr, _handle), this); + throw new AlpmException(_handle.SafeAlpmHandle); + return new PackageList(listPtr, _handle, this); } } diff --git a/Alpm/EnumerableWrapperEx.cs b/Alpm/EnumerableWrapperEx.cs new file mode 100644 index 0000000..6b688d4 --- /dev/null +++ b/Alpm/EnumerableWrapperEx.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Dynamic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Foodsoft.Alpm +{ + internal static class EnumerableWrapperEx + { + internal static EnumerableWrapperEx Create(THandle handle, + Func getItems, + Func getElement) where THandle : SafeHandle + { + return new EnumerableWrapperEx(handle, getItems, getElement); + } + } + + internal readonly struct EnumerableWrapperEx : ICollection where THandle : SafeHandle + { + private readonly THandle _handle; + private readonly Func _getItems; + private readonly Func _getElement; + + internal EnumerableWrapperEx(THandle handle, Func getItems, Func getElement) + { + _handle = handle; + _getItems = getItems; + _getElement = getElement; + } + + public IEnumerator GetEnumerator() + { + var release = false; + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + _handle.DangerousAddRef(ref release); + if (!release) throw new ObjectDisposedException(_handle.GetType().FullName); + for (var list = _getItems(_handle); list != IntPtr.Zero; list = Wrapper.ListNext(list)) + { + yield return _getElement(Wrapper.ListData(list)); + } + } + finally + { + if (release) + _handle.DangerousRelease(); + } + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public int Count + { + get + { + var getItems = _getItems; + var handle = _handle; + return handle.UseHandle((_) => (int) alpm.alpm_list_count(getItems(handle))); + } + } + + public bool Contains(TElement item) + { + var getItems = _getItems; + var getElement = _getElement; + var handle = _handle; + switch (item) + { + case string s: + return handle.UseHandle((_) => alpm.alpm_list_find_str(getItems(handle), s) != (IntPtr.Zero)); + default: + var comparer = EqualityComparer.Default; + return handle.UseHandle((_) => + { + for (var list = getItems(handle); list != IntPtr.Zero; list = Wrapper.ListNext(list)) + { + if (comparer.Equals(item, getElement(Wrapper.ListData(list)))) + return true; + } + + return false; + }); + } + } + + public void CopyTo(TElement[] array, int arrayIndex) + { + var getItems = _getItems; + var getElement = _getElement; + var handle = _handle; + handle.UseHandle((_) => + { + for (var list = getItems(handle); list != IntPtr.Zero; list = Wrapper.ListNext(list)) + { + array[arrayIndex++] = getElement(Wrapper.ListData(list)); + } + + return arrayIndex; + }); + } + + public void Add(TElement item) + { + throw new NotSupportedException(); + } + + public void Clear() + { + throw new NotSupportedException(); + } + + public bool Remove(TElement item) + { + throw new NotSupportedException(); + } + + public bool IsReadOnly => true; + } +} \ No newline at end of file diff --git a/Alpm/EnumerableWrapper`3.cs b/Alpm/EnumerableWrapper`3.cs index 3bdaed0..46b9a61 100644 --- a/Alpm/EnumerableWrapper`3.cs +++ b/Alpm/EnumerableWrapper`3.cs @@ -1,17 +1,31 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Dynamic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Foodsoft.Alpm { - internal struct EnumerableWrapper : IEnumerable where TImpl : struct, - IItemsReader - where THandle : SafeHandle + internal static class EnumerableWrapper + { + internal static EnumerableWrapper Create(TImpl impl) + where TImpl : struct, ICollectionImpl + { + return new EnumerableWrapper(impl); + } + } + + internal struct EnumerableWrapper : ICollection where TImpl : struct, + ICollectionImpl { private TImpl _impl; + public static EnumerableWrapper Create(TImpl impl) + { + return new EnumerableWrapper(impl); + } + public EnumerableWrapper(TImpl impl) { _impl = impl; @@ -40,5 +54,67 @@ namespace Foodsoft.Alpm } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public int Count + { + get + { + var impl = _impl; + return impl.Handle.UseHandle((_) => (int) alpm.alpm_list_count(impl.GetItems())); + } + } + + public bool Contains(TElement item) + { + var impl = _impl; + switch (item) + { + case string s: + return impl.Handle.UseHandle((_) => alpm.alpm_list_find_str(impl.GetItems(), s) != (IntPtr.Zero)); + default: + var comparer = EqualityComparer.Default; + return _impl.Handle.UseHandle((_) => + { + for (var list = impl.GetItems(); list != IntPtr.Zero; list = Wrapper.ListNext(list)) + { + if (comparer.Equals(item, impl.PtrToItem(Wrapper.ListData(list)))) + return true; + } + + return false; + }); + } + } + + public void CopyTo(TElement[] array, int arrayIndex) + { + var impl = _impl; + impl.Handle.UseHandle((_) => + { + for (var list = impl.GetItems(); list != IntPtr.Zero; list = Wrapper.ListNext(list)) + { + array[arrayIndex++] = impl.PtrToItem(Wrapper.ListData(list)); + } + + return arrayIndex; + }); + } + + public void Add(TElement item) + { + throw new NotSupportedException(); + } + + public void Clear() + { + throw new NotSupportedException(); + } + + public bool Remove(TElement item) + { + throw new NotSupportedException(); + } + + public bool IsReadOnly => true; } } \ No newline at end of file diff --git a/Alpm/Enums.cs b/Alpm/Enums.cs new file mode 100644 index 0000000..1649a7e --- /dev/null +++ b/Alpm/Enums.cs @@ -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) + } +} \ No newline at end of file diff --git a/Alpm/Exception.cs b/Alpm/Exception.cs deleted file mode 100644 index daa1325..0000000 --- a/Alpm/Exception.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Runtime.Serialization; -using Foodsoft.Alpm; - -namespace Foodsoft.Alpm -{ - [Serializable()] - public class Exception : System.Exception - { - public Exception() { } - internal Exception(SafeAlpmHandle handle) : base(alpm.alpm_strerror(alpm.alpm_errno(handle))) { } - public Exception(ErrNo errno) : base(alpm.alpm_strerror(errno)) { } - public Exception(ErrNo errno, System.Exception inner) : base(alpm.alpm_strerror(errno), inner) { } - - protected Exception(SerializationInfo info, - StreamingContext context) : base(info, context) { } - } -} \ No newline at end of file diff --git a/Alpm/FilePackage.cs b/Alpm/FilePackage.cs new file mode 100644 index 0000000..85a2fb2 --- /dev/null +++ b/Alpm/FilePackage.cs @@ -0,0 +1,11 @@ +namespace Foodsoft.Alpm +{ + public class FilePackage : Package + { + // ReSharper disable once SuggestBaseTypeForParameter + internal FilePackage(SafeFilePackageHandle handle) : base(handle) + { + + } + } +} \ No newline at end of file diff --git a/Alpm/Handle.cs b/Alpm/Handle.cs index ded90b4..1840a6c 100644 --- a/Alpm/Handle.cs +++ b/Alpm/Handle.cs @@ -13,7 +13,7 @@ namespace Foodsoft.Alpm _handle = alpm.alpm_initialize(root, dbpath, out var err); if (_handle.IsInvalid) { - throw new Exception(err); + throw new AlpmException(err); } } @@ -28,7 +28,7 @@ namespace Foodsoft.Alpm // managed by the alpm handle. if (ptr == IntPtr.Zero) { - throw new Exception(_handle); + throw new AlpmException(_handle); } return new Database(new SafeDatabaseHandle(ptr, _handle)); @@ -36,40 +36,28 @@ namespace Foodsoft.Alpm public Database LocalDB => ToDatabase(alpm.alpm_get_localdb(_handle)); - public Database RegisterSyncDB(string treename, SigLevel sigLevel) => + public Database RegisterSyncDB(string treename, SigLevel sigLevel = 0) => ToDatabase(alpm.alpm_register_syncdb(_handle, treename, sigLevel)); + + public void AddCacheDir(string dir) => API.WrapError(_handle, () => alpm.alpm_option_add_cachedir(_handle, dir)); + public bool RemoveCacheDir(string dir) => API.WrapErrorBool(_handle, () => alpm.alpm_option_add_cachedir(_handle, dir)); - private readonly struct CacheDirsAccessor : IItemsAccessor + private readonly struct CacheDirsImpl : ICollectionImpl { - internal CacheDirsAccessor(SafeAlpmHandle safeAlpmHandle) - { - SafeAlpmHandle = safeAlpmHandle; - } - - public SafeAlpmHandle SafeAlpmHandle { get; } - public IntPtr GetItems() => alpm.alpm_option_get_cachedirs(SafeAlpmHandle); - public int SetItems(IntPtr list) => alpm.alpm_option_set_cachedirs(SafeAlpmHandle, list); - public int AddItem(string item) => alpm.alpm_option_add_cachedir(SafeAlpmHandle, item); - public int RemoveItem(string item) => alpm.alpm_option_remove_cachedir(SafeAlpmHandle, item); - public IntPtr FindItem(string item) => alpm.alpm_list_find_str(GetItems(), item); + private readonly SafeAlpmHandle _handle; + internal CacheDirsImpl(SafeAlpmHandle handle) => _handle = handle; + public SafeHandle Handle => _handle; + public IntPtr GetItems() => alpm.alpm_option_get_cachedirs(_handle); public string PtrToItem(IntPtr p) => Marshal.PtrToStringUTF8(p)!; } - + public ICollection CacheDirs { - get => new CollectionWrapper(new CacheDirsAccessor(_handle)); - set - { - foreach (var s in value) - { - API.WrapError(_handle, () => alpm.alpm_option_add_cachedir(_handle, s)); - } - } + get => + EnumerableWrapperEx.Create(_handle, alpm.alpm_option_get_cachedirs, Marshal.PtrToStringUTF8!); + set => Wrapper.SetStringCollection(value, _handle, (s) => alpm.alpm_option_add_cachedir(_handle, s)); } - public bool ShouldIgnorePackage(Package pkg) - { - return alpm.alpm_pkg_should_ignore(_handle, pkg.Handle) == 0; - } + public bool ShouldIgnorePackage(Package pkg) => alpm.alpm_pkg_should_ignore(_handle, pkg.Handle) == 0; } } \ No newline at end of file diff --git a/Alpm/IAlpmItemsAccessor`1.cs b/Alpm/IAlpmItemsAccessor`1.cs deleted file mode 100644 index 3cad288..0000000 --- a/Alpm/IAlpmItemsAccessor`1.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Foodsoft.Alpm -{ - internal interface IItemsAccessor - { - SafeAlpmHandle SafeAlpmHandle { get; } - public IntPtr GetItems(); - public int SetItems(IntPtr list); - public int AddItem(TElement item); - public int RemoveItem(TElement item); - public IntPtr FindItem(TElement item); - public TElement PtrToItem(IntPtr p); - } -} \ No newline at end of file diff --git a/Alpm/IItemsReader`2.cs b/Alpm/IItemsReader`2.cs index 0d442d7..cf4bbc7 100644 --- a/Alpm/IItemsReader`2.cs +++ b/Alpm/IItemsReader`2.cs @@ -3,9 +3,9 @@ using System.Runtime.InteropServices; namespace Foodsoft.Alpm { - internal interface IItemsReader where THandle : SafeHandle + internal interface ICollectionImpl { - public THandle Handle { get; } + public SafeHandle Handle { get; } public IntPtr GetItems(); public TElement PtrToItem(IntPtr p); } diff --git a/Alpm/IPackageData.cs b/Alpm/IPackageData.cs index 82f204c..0ef3b20 100644 --- a/Alpm/IPackageData.cs +++ b/Alpm/IPackageData.cs @@ -44,15 +44,15 @@ namespace Foodsoft.Alpm public long Size { get; } public long InstalledSize { get; } public InstallReason InstallReason { get; } - public IEnumerable Licenses { get; } - public IReadOnlyCollection Groups { get; } - public IReadOnlyCollection Depends { get; } - public IReadOnlyCollection OptDepends { get; } - public IReadOnlyCollection CheckDepends { get; } - public IReadOnlyCollection MakeDepends { get; } - public IReadOnlyCollection Conflicts { get; } - public IReadOnlyCollection Provides { get; } - public IReadOnlyCollection Replaces { get; } + public ICollection Licenses { get; } + public ICollection Groups { get; } + public ICollection Depends { get; } + public ICollection OptDepends { get; } + public ICollection CheckDepends { get; } + public ICollection MakeDepends { get; } + public ICollection Conflicts { get; } + public ICollection Provides { get; } + public ICollection Replaces { get; } public IReadOnlyList FileList { get; } public IReadOnlyList Backup { get; } public string Base64Signature { get; } diff --git a/Alpm/Junk.cs b/Alpm/Junk.cs index 1946f95..2e27b85 100644 --- a/Alpm/Junk.cs +++ b/Alpm/Junk.cs @@ -80,20 +80,7 @@ namespace Foodsoft.Alpm } /** PGP signature verification options */ - [Flags] - public enum SigLevel - { - SIG_PACKAGE = (1 << 0), - SIG_PACKAGE_OPTIONAL = (1 << 1), - SIG_PACKAGE_MARGINAL_OK = (1 << 2), - SIG_PACKAGE_UNKNOWN_OK = (1 << 3), - SIG_DATABASE = (1 << 10), - SIG_DATABASE_OPTIONAL = (1 << 11), - SIG_DATABASE_MARGINAL_OK = (1 << 12), - SIG_DATABASE_UNKNOWN_OK = (1 << 13), - SIG_USE_DEFAULT = (1 << 31) - } /** PGP signature verification status return codes */ enum alpm_sigstatus_t diff --git a/Alpm/Package.cs b/Alpm/Package.cs index 54132e1..45f153e 100644 --- a/Alpm/Package.cs +++ b/Alpm/Package.cs @@ -31,21 +31,24 @@ namespace Foodsoft.Alpm public long InstalledSize => alpm.alpm_pkg_get_isize(Handle); public InstallReason InstallReason => alpm.alpm_pkg_get_reason(Handle); - public IEnumerable Licenses { get; } - public IReadOnlyCollection Groups { get; } - public IReadOnlyCollection Depends { get; } - public IReadOnlyCollection OptDepends { get; } - public IReadOnlyCollection CheckDepends { get; } - public IReadOnlyCollection MakeDepends { get; } - public IReadOnlyCollection Conflicts { get; } - public IReadOnlyCollection Provides { get; } - public IReadOnlyCollection Replaces { get; } + public ICollection Licenses => + EnumerableWrapperEx.Create(Handle, alpm.alpm_pkg_get_licenses, Marshal.PtrToStringUTF8!); + + public ICollection Groups { get; } + public ICollection Depends { get; } + public ICollection OptDepends { get; } + public ICollection CheckDepends { get; } + public ICollection MakeDepends { get; } + public ICollection Conflicts { get; } + public ICollection Provides { get; } + public ICollection Replaces { get; } public IReadOnlyList FileList { get; } public IReadOnlyList Backup { get; } public string Base64Signature { get; } public ValidationType Validation { get; } public bool HasScriptlet { get; } public long DownloadSize { get; } + public bool CheckMD5Sum() { throw new NotImplementedException(); @@ -53,21 +56,24 @@ namespace Foodsoft.Alpm public virtual Database? DB => null; - public IEnumerator ComputeRequiredBy() + public IEnumerator ComputeRequiredBy() { throw new NotImplementedException(); } - public IEnumerator ComputeOptionalFor() + public IEnumerator ComputeOptionalFor() { throw new NotImplementedException(); } - public void Dispose() { Handle.Dispose(); } + + public static int VersionCompare(string v1, string v2) + { + return alpm.alpm_pkg_vercmp(v1, v2); + } } - } \ No newline at end of file diff --git a/Alpm/PackageList.cs b/Alpm/PackageList.cs index 1bf86e5..77b1412 100644 --- a/Alpm/PackageList.cs +++ b/Alpm/PackageList.cs @@ -2,39 +2,42 @@ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Foodsoft.Alpm { - public struct PackageList : IEnumerable, IDisposable + public class PackageList : ICollection { - private SafeListHandle _handle; - private Database _db; + private readonly SafeDatabaseHandle _parentHandle; + private readonly IntPtr _listPtr; + private readonly Database _db; - internal PackageList(SafeListHandle handle, Database db) + internal PackageList(IntPtr listPtr, SafeDatabaseHandle parentHandle, Database db) { - _handle = handle; + _parentHandle = parentHandle; + _listPtr = listPtr; _db = db; } - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { var release = false; - + RuntimeHelpers.PrepareConstrainedRegions(); try { - _handle.DangerousAddRef(ref release); - if (!release) throw new ObjectDisposedException(_handle.GetType().FullName); - for (var list = _handle.DangerousGetHandle(); list != IntPtr.Zero; list = Wrapper.ListNext(list)) + _parentHandle.DangerousAddRef(ref release); + if (!release) throw new ObjectDisposedException(_parentHandle.GetType().FullName); + for (var list = _listPtr; list != IntPtr.Zero; list = Wrapper.ListNext(list)) { yield return new CachePackage( - new SafeCachePackageHandle(Wrapper.ListData(list), _handle.ParentHandle), _db); + new SafeCachePackageHandle(Wrapper.ListData(list), _parentHandle), _db); } } finally { if (release) - _handle.DangerousRelease(); + _parentHandle.DangerousRelease(); } } @@ -42,10 +45,51 @@ namespace Foodsoft.Alpm { return GetEnumerator(); } - - public void Dispose() + public bool Contains(CachePackage item) { - _handle.Dispose(); + var name = item.Name; + + return _parentHandle.UseHandle(_listPtr, (list) => + { + for (; list != IntPtr.Zero; list = Wrapper.ListNext(list)) + { + if (name == alpm.alpm_pkg_get_name(list)) + return true; + } + + return false; + }); } + + public void CopyTo(CachePackage[] array, int arrayIndex) + { + _parentHandle.UseHandle(_listPtr,(list) => + { + for (; list != IntPtr.Zero; list = Wrapper.ListNext(list)) + { + array[arrayIndex++] = new CachePackage( + new SafeCachePackageHandle(Wrapper.ListData(list), _parentHandle), _db); + } + return 0; + }); + } + + public void Add(CachePackage item) + { + throw new NotSupportedException(); + } + + public bool Remove(CachePackage item) + { + throw new NotSupportedException(); + } + public void Clear() + { + throw new NotSupportedException(); + } + + public int Count => _parentHandle.UseHandle(_listPtr,(list) => (int) alpm.alpm_list_count(list)); + + public bool IsReadOnly => true; } } \ No newline at end of file diff --git a/Alpm/SafeCachePackageHandle.cs b/Alpm/SafeCachePackageHandle.cs index 1b70949..0f44831 100644 --- a/Alpm/SafeCachePackageHandle.cs +++ b/Alpm/SafeCachePackageHandle.cs @@ -1,17 +1,29 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; namespace Foodsoft.Alpm { internal sealed class SafeCachePackageHandle : SafePackageHandle { - internal SafeAlpmHandle SafeAlpmHandle => SafeDatabaseHandle.SafeAlpmHandle; - internal SafeDatabaseHandle SafeDatabaseHandle { get; } = null!; + internal SafeAlpmHandle SafeAlpmHandle + { + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [PrePrepareMethod] + get => SafeDatabaseHandle.SafeAlpmHandle; + } + + internal SafeDatabaseHandle SafeDatabaseHandle + { + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [PrePrepareMethod] + get; + } = null!; [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] [PrePrepareMethod] - internal SafeCachePackageHandle(IntPtr ptr, SafeDatabaseHandle dbHandle) + internal SafeCachePackageHandle(IntPtr ptr, SafeDatabaseHandle parentHandle) : base() { var success = false; @@ -20,10 +32,10 @@ namespace Foodsoft.Alpm try { } finally { - dbHandle.DangerousAddRef(ref success); + parentHandle.DangerousAddRef(ref success); if (success) { - SafeDatabaseHandle = dbHandle; + SafeDatabaseHandle = parentHandle; handle = ptr; } } @@ -36,11 +48,5 @@ namespace Foodsoft.Alpm SafeDatabaseHandle.DangerousRelease(); return true; } - - public override bool IsInvalid - { - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), PrePrepareMethod] - get => handle == IntPtr.Zero; - } } } \ No newline at end of file diff --git a/Alpm/SafeDatabaseHandle.cs b/Alpm/SafeDatabaseHandle.cs index 3144625..6dd7152 100644 --- a/Alpm/SafeDatabaseHandle.cs +++ b/Alpm/SafeDatabaseHandle.cs @@ -12,12 +12,11 @@ namespace Foodsoft.Alpm [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [PrePrepareMethod] get; - } = null!; // we always throw in the constructor on failure + } = null!; [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] [PrePrepareMethod] - internal SafeDatabaseHandle(IntPtr dbPtr, SafeAlpmHandle safeAlpmHandle) - : base(IntPtr.Zero, true) + internal SafeDatabaseHandle(IntPtr dbPtr, SafeAlpmHandle safeAlpmHandle) : base(IntPtr.Zero, true) { var success = false; @@ -39,8 +38,9 @@ namespace Foodsoft.Alpm [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), PrePrepareMethod] protected override bool ReleaseHandle() { + var err = alpm.alpm_db_unregister(handle); SafeAlpmHandle.DangerousRelease(); - return true; + return err == 0; } public override bool IsInvalid diff --git a/Alpm/SafeFilePackageHandle.cs b/Alpm/SafeFilePackageHandle.cs new file mode 100644 index 0000000..8a37aea --- /dev/null +++ b/Alpm/SafeFilePackageHandle.cs @@ -0,0 +1,39 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; + +namespace Foodsoft.Alpm +{ + internal class SafeFilePackageHandle : SafePackageHandle + { + internal SafeAlpmHandle SafeAlpmHandle { get; } = null!; + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + [PrePrepareMethod] + internal SafeFilePackageHandle(IntPtr ptr, SafeAlpmHandle parentHandle) + { + var success = false; + + RuntimeHelpers.PrepareConstrainedRegions(); + try { } + finally + { + parentHandle.DangerousAddRef(ref success); + if (success) + { + SafeAlpmHandle = parentHandle; + handle = ptr; + } + } + + if (!success) throw new ObjectDisposedException(GetType().FullName); + } + + protected override bool ReleaseHandle() + { + SafeAlpmHandle.DangerousRelease(); + return true; + } + } +} \ No newline at end of file diff --git a/Alpm/SafePackageHandle.cs b/Alpm/SafePackageHandle.cs index 33f1cc9..363d4cb 100644 --- a/Alpm/SafePackageHandle.cs +++ b/Alpm/SafePackageHandle.cs @@ -4,13 +4,9 @@ using System.Runtime.InteropServices; namespace Foodsoft.Alpm { - internal class SafePackageHandle : SafeHandle + internal abstract class SafePackageHandle : SafeHandle { protected SafePackageHandle() : base(IntPtr.Zero, true) { } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), PrePrepareMethod] - protected override bool ReleaseHandle() => alpm.alpm_pkg_free(handle) == 0; - public override bool IsInvalid { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), PrePrepareMethod] diff --git a/Alpm/UTF8InMarshaler.cs b/Alpm/UTF8InMarshaler.cs index e51df4e..44d426d 100644 --- a/Alpm/UTF8InMarshaler.cs +++ b/Alpm/UTF8InMarshaler.cs @@ -14,30 +14,14 @@ namespace Foodsoft.Alpm { if (pNativeData == IntPtr.Zero) return; - Marshal.FreeHGlobal(pNativeData); + Marshal.FreeCoTaskMem(pNativeData); } public int GetNativeDataSize() => -1; - public unsafe IntPtr MarshalManagedToNative(object? managedObj) + public IntPtr MarshalManagedToNative(object? managedObj) { - if (managedObj is null) return IntPtr.Zero; - - var s = (string) managedObj; - - var nb = Encoding.UTF8.GetMaxByteCount(s.Length); - - var pMem = Marshal.AllocHGlobal(nb + 1); - var pbMem = (byte*) pMem; - - int nbWritten; - fixed (char* firstChar = s) - { - nbWritten = Encoding.UTF8.GetBytes(firstChar, s.Length, pbMem, nb); - } - - pbMem[nbWritten] = 0; - return pMem; + return Marshal.StringToCoTaskMemUTF8((string?) managedObj); } public object MarshalNativeToManaged(IntPtr pNativeData) diff --git a/Alpm/Wrapper.cs b/Alpm/Wrapper.cs index bb06c11..1951014 100644 --- a/Alpm/Wrapper.cs +++ b/Alpm/Wrapper.cs @@ -1,4 +1,8 @@ using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Foodsoft.Alpm { @@ -6,5 +10,37 @@ namespace Foodsoft.Alpm { internal static unsafe IntPtr ListNext(IntPtr list) => ((alpm_list_t*) list)->next; internal static unsafe IntPtr ListData(IntPtr list) => ((alpm_list_t*) list)->data; + + internal static TResult UseHandle(this SafeHandle handle, IntPtr ptr, Func op) + { + var release = false; + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + handle.DangerousAddRef(ref release); + if (!release) throw new ObjectDisposedException(handle.GetType().FullName); + return op(ptr); + } + finally + { + if (release) + handle.DangerousRelease(); + } + } + + internal static TResult UseHandle(this SafeHandle handle, Func op) => + handle.UseHandle(handle.DangerousGetHandle(), op); + + internal static void SetStringCollection(IEnumerable value, SafeAlpmHandle safeAlpmHandle, Func op) + { + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var s in value) + { + if (op(s) < 0) + throw new AlpmException(safeAlpmHandle); + } + } + } } \ No newline at end of file diff --git a/Alpm/alpm.cs b/Alpm/alpm.cs index 7cb4d0d..0edd52b 100644 --- a/Alpm/alpm.cs +++ b/Alpm/alpm.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Runtime.InteropServices.WindowsRuntime; using Foodsoft.Alpm; @@ -31,7 +32,11 @@ namespace Foodsoft.Alpm [DllImport(nameof(alpm))] [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))] public static extern string alpm_pkg_get_name(SafePackageHandle pkg); - + + [DllImport(nameof(alpm))] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))] + public static extern string alpm_pkg_get_name(IntPtr pkg); + [DllImport(nameof(alpm))] [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))] public static extern string alpm_pkg_get_version(SafePackageHandle pkg); @@ -79,8 +84,7 @@ namespace Foodsoft.Alpm public static extern InstallReason alpm_pkg_get_reason(SafePackageHandle pkg); [DllImport(nameof(alpm))] - [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))] - public static extern string alpm_pkg_get_licenses(SafePackageHandle pkg); + public static extern IntPtr alpm_pkg_get_licenses(SafePackageHandle pkg); [DllImport(nameof(alpm))] [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))] @@ -115,8 +119,7 @@ namespace Foodsoft.Alpm [DllImport(nameof(alpm))] public static extern int alpm_pkg_free(IntPtr ptr); - - + [DllImport(nameof(alpm))] public static extern IntPtr alpm_option_get_cachedirs(SafeAlpmHandle handle); @@ -124,12 +127,14 @@ namespace Foodsoft.Alpm public static extern int alpm_option_set_cachedirs(SafeAlpmHandle handle, IntPtr cachedirs); [DllImport(nameof(alpm))] - public static extern int alpm_option_add_cachedir(SafeAlpmHandle handle, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] string cachedir); + public static extern int alpm_option_add_cachedir(SafeAlpmHandle handle, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] + string cachedir); [DllImport(nameof(alpm))] - public static extern int alpm_option_remove_cachedir(SafeAlpmHandle handle, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] string cachedir); + public static extern int alpm_option_remove_cachedir(SafeAlpmHandle handle, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] + string cachedir); [DllImport(nameof(alpm))] public static extern ErrNo alpm_errno(SafeAlpmHandle handle); @@ -145,13 +150,23 @@ namespace Foodsoft.Alpm public static extern unsafe alpm_list_t* alpm_option_get_syncdbs(); [DllImport(nameof(alpm))] - public static extern IntPtr alpm_register_syncdb(SafeAlpmHandle handle, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] string treename, SigLevel sigLevel); + public static extern IntPtr alpm_register_syncdb(SafeAlpmHandle handle, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] + string treename, SigLevel sigLevel); [DllImport(nameof(alpm))] public static extern int alpm_db_unregister_all_syncdbs(SafeAlpmHandle handle); [DllImport(nameof(alpm))] - public static extern unsafe alpm_list_t* alpm_list_next(alpm_list_t* list); + public static extern IntPtr alpm_list_add(IntPtr list, IntPtr item); + + [DllImport(nameof(alpm))] + public static extern IntPtr alpm_list_append_strdup(ref IntPtr list, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] + string str); + + [DllImport(nameof(alpm))] + public static extern IntPtr alpm_list_next(IntPtr list); [DllImport(nameof(alpm))] public static extern UIntPtr alpm_list_count(IntPtr list); @@ -159,8 +174,16 @@ namespace Foodsoft.Alpm [DllImport(nameof(alpm))] public static extern void alpm_list_free(IntPtr list); + // ReSharper disable once InconsistentNaming + public delegate void alpm_fn_free(IntPtr ptr); + [DllImport(nameof(alpm))] - public static extern IntPtr alpm_list_find_str(IntPtr list, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] string needle); + public static extern void alpm_list_free_inner(IntPtr list, alpm_fn_free freeFn); + + [DllImport(nameof(alpm))] + public static extern IntPtr alpm_list_find_str(IntPtr list, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8InMarshaler))] + string needle); [DllImport(nameof(alpm))] public static extern int alpm_unlock(Handle handle); @@ -187,7 +210,7 @@ namespace Foodsoft.Alpm string url); [DllImport(nameof(alpm))] - public static extern int alpm_db_unregister(SafeDatabaseHandle db); + public static extern int alpm_db_unregister(IntPtr db); [DllImport(nameof(alpm))] [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8OutMarshaler))] @@ -221,5 +244,7 @@ namespace Foodsoft.Alpm [DllImport(nameof(alpm))] public static extern IntPtr alpm_db_get_pkgcache(SafeDatabaseHandle db); + [DllImport(nameof(alpm))] + public static extern int alpm_pkg_vercmp(string v1, string v2); } } \ No newline at end of file diff --git a/DotNetAlpm.sln b/DotNetAlpm.sln index 62cb70e..d54d580 100644 --- a/DotNetAlpm.sln +++ b/DotNetAlpm.sln @@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Alpm", "Alpm\Alpm.csproj", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples", "Samples\Samples.csproj", "{1215BE9E-B4F4-4F42-B4A2-E890C5EAA903}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Alpm.Tests", "Alpm.Tests\Alpm.Tests.csproj", "{96EA63C3-18AE-4CE4-9C87-61A3CAC477AD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -18,5 +20,9 @@ Global {1215BE9E-B4F4-4F42-B4A2-E890C5EAA903}.Debug|Any CPU.Build.0 = Debug|Any CPU {1215BE9E-B4F4-4F42-B4A2-E890C5EAA903}.Release|Any CPU.ActiveCfg = Release|Any CPU {1215BE9E-B4F4-4F42-B4A2-E890C5EAA903}.Release|Any CPU.Build.0 = Release|Any CPU + {96EA63C3-18AE-4CE4-9C87-61A3CAC477AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96EA63C3-18AE-4CE4-9C87-61A3CAC477AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96EA63C3-18AE-4CE4-9C87-61A3CAC477AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96EA63C3-18AE-4CE4-9C87-61A3CAC477AD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/DotNetAlpm.sln.DotSettings b/DotNetAlpm.sln.DotSettings index 58ae2f7..eef92bb 100644 --- a/DotNetAlpm.sln.DotSettings +++ b/DotNetAlpm.sln.DotSettings @@ -1,2 +1,9 @@  - True \ No newline at end of file + True + True + True + True + True + True + True + True \ No newline at end of file diff --git a/Samples/Program.cs b/Samples/Program.cs index 4d5ca61..08304cb 100644 --- a/Samples/Program.cs +++ b/Samples/Program.cs @@ -1,39 +1,103 @@ using System; +using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; using Foodsoft.Alpm; +// ReSharper disable once UnusedType.Global namespace Samples { - class Program + [Example("installed")] + internal class Installed : IExample { - static void Other() + public int Run(string[] args) { - using var h = new Handle("/", "/home/luebsj/db"); - using var db = h.RegisterSyncDB("jkl-repo", SigLevel.SIG_PACKAGE_OPTIONAL | SigLevel.SIG_USE_DEFAULT); - - db.AddServer("http://arch.johnluebs.com/x86_64"); - db.Update(false); - foreach (var a in db.Servers) - { - Console.WriteLine("Hello {0}", a); - } + using var h = new Handle("/", "/var/lib/pacman"); + using var db = h.LocalDB; - var servers = db.Servers; - var b = new string[3]; - var l = db.Servers.ToImmutableList(); + foreach (var pkg in db.PackageCache) + using (pkg) + { + Console.WriteLine("{0} {1}", pkg.Name, pkg.Version); + } - using var cache = db.PackageCache; - foreach ( var p in cache) using(p) - { - Console.WriteLine("Hello: {0} {1} {2}", p.Name, p.Filename, p.BuildDate); - } - - Console.WriteLine("Hello World! {0} {1} {2}", db.Name, API.Version, - l[0]); + return 0; } - static void Main(string[] args) + } + + [Example("search")] + internal class Search : IExample + { + public int Run(string[] args) { - Other(); + using var h = new Handle("/", "/var/lib/pacman"); + using var db = h.RegisterSyncDB("core"); + db.Servers = new[]{"http://www.google.com"}; + db.Update(true); + + foreach (var pkg in db.PackageCache) + using (pkg) + { + Console.WriteLine("{0} {1} {2}", pkg.Name, pkg.Version, pkg.Description); + } + + return 0; } } } + +namespace Samples +{ + internal static class Program + { + private static int Main(string[] args) + { + var examples = (from t in Assembly.GetExecutingAssembly().GetTypes() + let attribute = (Example?) t.GetCustomAttribute(typeof(Example)) + where attribute != null + select new {Name = attribute.Name, Type = t}).ToImmutableDictionary((e) => e.Name); + + if (args.Length < 1) + { + Console.Error.WriteLine("Sample"); + foreach (var example in examples.Values) + { + Console.Error.WriteLine("{0}", example.Name); + } + + return 1; + } + + int ret; + try + { + ret = ((IExample) Activator.CreateInstance(examples[args[0]].Type)!).Run(args); + } + catch (AlpmException e) + { + Console.Error.WriteLine("{0}", e.Message); + return 1; + } + + return ret; + } + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)] + public class Example : Attribute + { + public string Name { get; } + + public Example(string name) + { + Name = name; + } + } + + public interface IExample + { + public int Run(string[] args); + } +} \ No newline at end of file diff --git a/Samples/Samples.csproj b/Samples/Samples.csproj index 5864e5b..0a964af 100644 --- a/Samples/Samples.csproj +++ b/Samples/Samples.csproj @@ -3,6 +3,7 @@ Exe netcoreapp3.1 + enable