From 9aa367e9f59fff6c7d55fa6f77c4bbc3d8911ec0 Mon Sep 17 00:00:00 2001 From: "John K. Luebs" Date: Thu, 30 Apr 2020 17:27:50 -0400 Subject: [PATCH] checkpoint --- Alpm.Tests/AlpmIntegrationTest.cs | 2 +- Alpm/API.cs | 24 ---------------- Alpm/Backup.cs | 6 +++- Alpm/CachePackageList.cs | 19 ++++++++---- Alpm/Database.cs | 23 +++++++++++++-- Alpm/Depend.cs | 13 +++++++-- Alpm/{Wrapper.cs => Detail.cs} | 30 +++++++++++++++++-- Alpm/EnumerableWrapper.cs | 12 ++++---- Alpm/Enums.cs | 9 ++++++ Alpm/ExtensionMethods.cs | 48 +++++++++++++++++++++++++++++++ Alpm/Handle.cs | 8 +++--- Alpm/IPackageData.cs | 20 ++++++------- Alpm/Junk.cs | 23 ++------------- Alpm/Package.cs | 20 ++++++------- Alpm/alpm.cs | 6 ++++ Samples/Program.cs | 11 +++---- 16 files changed, 176 insertions(+), 98 deletions(-) rename Alpm/{Wrapper.cs => Detail.cs} (62%) create mode 100644 Alpm/ExtensionMethods.cs diff --git a/Alpm.Tests/AlpmIntegrationTest.cs b/Alpm.Tests/AlpmIntegrationTest.cs index 3a30233..2ca8c0b 100644 --- a/Alpm.Tests/AlpmIntegrationTest.cs +++ b/Alpm.Tests/AlpmIntegrationTest.cs @@ -13,7 +13,7 @@ namespace Alpm.Tests public void TestLocalDB() { using var localDB = _handle.LocalDB; - Assert.True(localDB.CachePackageCache.Count() > 15); + Assert.True(localDB.PackageCache.Count() > 15); } [Fact] diff --git a/Alpm/API.cs b/Alpm/API.cs index ec9b2af..77ad969 100644 --- a/Alpm/API.cs +++ b/Alpm/API.cs @@ -5,29 +5,5 @@ namespace Foodsoft.Alpm public static class API { public static readonly string Version = alpm.alpm_version(); - - internal static void WrapError(SafeAlpmHandle h, Func f) - { - var err = f(); - if (err != 0) - { - throw new AlpmException(h); - } - } - - /* - * Handles the pattern where <0 is exceptional, but 1 is some "false" - * condition. - */ - internal static bool WrapErrorBool(SafeAlpmHandle h, Func f) - { - var err = f(); - if (err < 0) - { - throw new AlpmException(h); - } - return err == 0; - } - } } \ No newline at end of file diff --git a/Alpm/Backup.cs b/Alpm/Backup.cs index 3a8cbf9..f9d0dae 100644 --- a/Alpm/Backup.cs +++ b/Alpm/Backup.cs @@ -3,11 +3,15 @@ using System.Runtime.InteropServices; namespace Foodsoft.Alpm { - public struct Backup + public readonly struct Backup : IEquatable { public string Name { get; } public string Hash { get; } + public bool Equals(Backup other) => Name == other.Name && Hash == other.Hash; + public override bool Equals(object? obj) => obj is Backup other && Equals(other); + public override int GetHashCode() => HashCode.Combine(Name, Hash); + [StructLayout(LayoutKind.Sequential)] private readonly unsafe struct NativeBackup { diff --git a/Alpm/CachePackageList.cs b/Alpm/CachePackageList.cs index 8ea8e7c..f1ad4b3 100644 --- a/Alpm/CachePackageList.cs +++ b/Alpm/CachePackageList.cs @@ -1,10 +1,15 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; namespace Foodsoft.Alpm { + + public class CachePackageList : IPackageList, ICollection { private readonly SafeDatabaseHandle _parentHandle; @@ -17,7 +22,8 @@ namespace Foodsoft.Alpm _listPtr = listPtr; _db = db; } - + + [PrePrepareMethod] public IEnumerator GetEnumerator() { var release = false; @@ -27,10 +33,10 @@ namespace Foodsoft.Alpm { _parentHandle.DangerousAddRef(ref release); if (!release) throw new ObjectDisposedException(_parentHandle.GetType().FullName); - for (var list = _listPtr; list != IntPtr.Zero; list = Wrapper.ListNext(list)) + for (var list = _listPtr; list != IntPtr.Zero; list = Detail.ListNext(list)) { yield return new CachePackage( - new SafeCachePackageHandle(Wrapper.ListData(list), _parentHandle), _db); + new SafeCachePackageHandle(Detail.ListData(list), _parentHandle), _db); } } finally @@ -51,7 +57,7 @@ namespace Foodsoft.Alpm return _parentHandle.UseHandle(_listPtr, (list) => { - for (; list != IntPtr.Zero; list = Wrapper.ListNext(list)) + for (; list != IntPtr.Zero; list = Detail.ListNext(list)) { if (name == alpm.alpm_pkg_get_name(list)) return true; @@ -65,15 +71,16 @@ namespace Foodsoft.Alpm { _parentHandle.UseHandle(_listPtr, (list) => { - for (; list != IntPtr.Zero; list = Wrapper.ListNext(list)) + for (; list != IntPtr.Zero; list = Detail.ListNext(list)) { array[arrayIndex++] = new CachePackage( - new SafeCachePackageHandle(Wrapper.ListData(list), _parentHandle), _db); + new SafeCachePackageHandle(Detail.ListData(list), _parentHandle), _db); } return 0; }); } + public CachePackage? FindSatisfier(string depString) { return _parentHandle.UseHandle(_listPtr, (list) => diff --git a/Alpm/Database.cs b/Alpm/Database.cs index 4b69d4d..1ce0fb5 100644 --- a/Alpm/Database.cs +++ b/Alpm/Database.cs @@ -7,6 +7,16 @@ namespace Foodsoft.Alpm { public sealed class Database : IDisposable { + [Flags] + public enum UsageFlags + { + Sync = 1, + Search = (1 << 1), + Install = (1 << 2), + Upgrade = (1 << 3), + All = (1 << 4) - 1, + } + private readonly SafeDatabaseHandle _handle; internal Database(SafeDatabaseHandle handle) => _handle = handle; @@ -14,10 +24,10 @@ namespace Foodsoft.Alpm public void Unregister() => _handle.Close(); public void AddServer(string url) => - API.WrapError(_handle.SafeAlpmHandle, () => alpm.alpm_db_add_server(_handle, url)); + Detail.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)); + Detail.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. @@ -85,7 +95,7 @@ namespace Foodsoft.Alpm return new CachePackage(new SafeCachePackageHandle(pkgPtr, _handle), this); } - public CachePackageList CachePackageCache + public CachePackageList PackageCache { get { @@ -96,6 +106,13 @@ namespace Foodsoft.Alpm } } + public CachePackageList Search() + { + + } + + public UsageFlags Usage => Detail.WrapError(_handle.SafeAlpmHandle, _handle, alpm.alpm_db_get_usage); + public void Dispose() { _handle.Dispose(); diff --git a/Alpm/Depend.cs b/Alpm/Depend.cs index 0595b83..267b010 100644 --- a/Alpm/Depend.cs +++ b/Alpm/Depend.cs @@ -1,10 +1,11 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Drawing; using System.Runtime.InteropServices; namespace Foodsoft.Alpm { - public class Depend + public class Depend : IEquatable { public enum ModType { @@ -15,13 +16,20 @@ namespace Foodsoft.Alpm GreaterThan, LessThan } - + public string Name { get; } public string Version { get; } public string Description { get; } public ulong NameHash { get; } public ModType Mod { get; } + public override bool Equals(object? obj) => (obj is Depend other) && this.Equals(other); + + public bool Equals(Depend? other) => !ReferenceEquals(other, null) && ReferenceEquals(this, other) && + Name == other.Name && Version == other.Version && Mod == other.Mod; + + public override int GetHashCode() => HashCode.Combine(Name, Version, (int) Mod); + [StructLayout(LayoutKind.Sequential)] private readonly unsafe struct NativeDepend { @@ -41,6 +49,5 @@ namespace Foodsoft.Alpm NameHash = native->name_hash; Mod = native->mod; } - } } \ No newline at end of file diff --git a/Alpm/Wrapper.cs b/Alpm/Detail.cs similarity index 62% rename from Alpm/Wrapper.cs rename to Alpm/Detail.cs index 6f78736..2bcb7c8 100644 --- a/Alpm/Wrapper.cs +++ b/Alpm/Detail.cs @@ -5,7 +5,7 @@ using System.Runtime.InteropServices; namespace Foodsoft.Alpm { - internal static class Wrapper + internal static class Detail { internal static unsafe IntPtr ListNext(IntPtr list) => ((alpm_list_t*) list)->next; internal static unsafe IntPtr ListData(IntPtr list) => ((alpm_list_t*) list)->data; @@ -40,6 +40,32 @@ namespace Foodsoft.Alpm throw new AlpmException(safeAlpmHandle); } } - + + internal static void WrapError(SafeAlpmHandle alpmHandle, Func f) + { + var err = f(); + if (err != 0) + throw new AlpmException(alpmHandle); + } + + internal delegate int OutFunc(THandle handle, out T result); + + internal static T WrapError(SafeAlpmHandle alpmHandle, THandle handle, OutFunc f) + { + var err = f(handle, out var result); + if (err != 0) + throw new AlpmException(alpmHandle); + return result; + } + + internal static bool WrapErrorBool(SafeAlpmHandle h, Func f) + { + var err = f(); + if (err < 0) + { + throw new AlpmException(h); + } + return err == 0; + } } } \ No newline at end of file diff --git a/Alpm/EnumerableWrapper.cs b/Alpm/EnumerableWrapper.cs index 265b154..db0b669 100644 --- a/Alpm/EnumerableWrapper.cs +++ b/Alpm/EnumerableWrapper.cs @@ -50,9 +50,9 @@ namespace Foodsoft.Alpm { _handle.DangerousAddRef(ref release); if (!release) throw new ObjectDisposedException(_handle.GetType().FullName); - for (var list = _getItems(_handle); list != IntPtr.Zero; list = Wrapper.ListNext(list)) + for (var list = _getItems(_handle); list != IntPtr.Zero; list = Detail.ListNext(list)) { - yield return _getElement(Wrapper.ListData(list)); + yield return _getElement(Detail.ListData(list)); } } finally @@ -87,9 +87,9 @@ namespace Foodsoft.Alpm var comparer = EqualityComparer.Default; return handle.UseHandle((_) => { - for (var list = getItems(handle); list != IntPtr.Zero; list = Wrapper.ListNext(list)) + for (var list = getItems(handle); list != IntPtr.Zero; list = Detail.ListNext(list)) { - if (comparer.Equals(item, getElement(Wrapper.ListData(list)))) + if (comparer.Equals(item, getElement(Detail.ListData(list)))) return true; } @@ -105,9 +105,9 @@ namespace Foodsoft.Alpm var handle = _handle; handle.UseHandle((_) => { - for (var list = getItems(handle); list != IntPtr.Zero; list = Wrapper.ListNext(list)) + for (var list = getItems(handle); list != IntPtr.Zero; list = Detail.ListNext(list)) { - array[arrayIndex++] = getElement(Wrapper.ListData(list)); + array[arrayIndex++] = getElement(Detail.ListData(list)); } return arrayIndex; diff --git a/Alpm/Enums.cs b/Alpm/Enums.cs index 1649a7e..fb95cbd 100644 --- a/Alpm/Enums.cs +++ b/Alpm/Enums.cs @@ -2,6 +2,15 @@ using System; namespace Foodsoft.Alpm { + [Flags] + public enum LogLevel + { + Error = 1, + Warning = (1 << 1), + Debug = (1 << 2), + Function = (1 << 3) + } + [Flags] public enum SigLevel { diff --git a/Alpm/ExtensionMethods.cs b/Alpm/ExtensionMethods.cs new file mode 100644 index 0000000..befcf0a --- /dev/null +++ b/Alpm/ExtensionMethods.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; + +namespace Foodsoft.Alpm +{ + public static class ExtensionMethods + { + [PrePrepareMethod] + public static Package? FindSatisfier(this IEnumerable pkgList, string depString) + { + var refs = new Dictionary(10); + var listPtr = IntPtr.Zero; + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + foreach (var pkg in pkgList) + { + var release = false; + var handle = pkg.Handle; + var pkgPtr = handle.DangerousGetHandle(); + + refs.Add(pkgPtr, null); + handle.DangerousAddRef(ref release); + if (!release) throw new ObjectDisposedException(handle.GetType().FullName); + + refs[pkgPtr] = pkg; + listPtr = alpm.alpm_list_add(listPtr, handle.DangerousGetHandle()); + } + + var foundPtr = alpm.alpm_find_satisfier(listPtr, depString); + return foundPtr != IntPtr.Zero + ? refs[foundPtr] + : null; + } + finally + { + alpm.alpm_list_free(listPtr); + foreach (var pkg in refs.Values) + { + pkg?.Handle.DangerousRelease(); + } + } + } + } +} \ No newline at end of file diff --git a/Alpm/Handle.cs b/Alpm/Handle.cs index 3f1687f..1df2a31 100644 --- a/Alpm/Handle.cs +++ b/Alpm/Handle.cs @@ -7,7 +7,7 @@ namespace Foodsoft.Alpm public sealed class Handle : IDisposable { private readonly SafeAlpmHandle _handle; - + public Handle(string root, string dbpath) { _handle = alpm.alpm_initialize(root, dbpath, out var err); @@ -39,13 +39,13 @@ namespace Foodsoft.Alpm 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)); + public void AddCacheDir(string dir) => Detail.WrapError(_handle, () => alpm.alpm_option_add_cachedir(_handle, dir)); + public bool RemoveCacheDir(string dir) => Detail.WrapErrorBool(_handle, () => alpm.alpm_option_add_cachedir(_handle, dir)); public ICollection CacheDirs { get => EnumerableWrapper.Create(_handle, alpm.alpm_option_get_cachedirs); - set => Wrapper.SetStringCollection(value, _handle, (s) => alpm.alpm_option_add_cachedir(_handle, s)); + set => Detail.SetStringCollection(value, _handle, (s) => alpm.alpm_option_add_cachedir(_handle, s)); } public bool ShouldIgnorePackage(Package pkg) => alpm.alpm_pkg_should_ignore(_handle, pkg.Handle) == 0; diff --git a/Alpm/IPackageData.cs b/Alpm/IPackageData.cs index 86370fd..bc6b208 100644 --- a/Alpm/IPackageData.cs +++ b/Alpm/IPackageData.cs @@ -44,17 +44,17 @@ namespace Foodsoft.Alpm public long Size { get; } public long InstalledSize { get; } public InstallReason InstallReason { 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 IEnumerable Licenses { get; } + public IEnumerable Groups { get; } + public IEnumerable Depends { get; } + public IEnumerable OptDepends { get; } + public IEnumerable CheckDepends { get; } + public IEnumerable MakeDepends { get; } + public IEnumerable Conflicts { get; } + public IEnumerable Provides { get; } + public IEnumerable Replaces { get; } public IReadOnlyList Files { get; } - public ICollection Backup { get; } + public IEnumerable Backup { get; } public string Base64Signature { get; } public ValidationType Validation { get; } public bool HasScriptlet { get; } diff --git a/Alpm/Junk.cs b/Alpm/Junk.cs index 2e27b85..c1981ab 100644 --- a/Alpm/Junk.cs +++ b/Alpm/Junk.cs @@ -102,28 +102,8 @@ namespace Foodsoft.Alpm SIGVALIDITY_UNKNOWN } - /** Dependency */ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public struct alpm_depend_t - { - string name; - string version; - string desc; - public ulong name_hash; - public alpm_depmod_t mod; - } - - [StructLayout(LayoutKind.Sequential)] - public struct AlpmDependPtr - { - private IntPtr ptr; - - public alpm_depend_t Unmarshal() - { - return Marshal.PtrToStructure(ptr); - } - } +#if JUNK_INCLUDE /** Missing dependency */ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct alpm_depmissing_t @@ -146,6 +126,7 @@ namespace Foodsoft.Alpm public string package2; public AlpmDependPtr reason; } +#endif [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] /** File conflict */ diff --git a/Alpm/Package.cs b/Alpm/Package.cs index e98e065..0e2f7c8 100644 --- a/Alpm/Package.cs +++ b/Alpm/Package.cs @@ -30,21 +30,21 @@ namespace Foodsoft.Alpm public long Size => alpm.alpm_pkg_get_size(Handle); public long InstalledSize => alpm.alpm_pkg_get_isize(Handle); public InstallReason InstallReason => alpm.alpm_pkg_get_reason(Handle); - public ICollection Licenses => + public IEnumerable Licenses => EnumerableWrapper.Create(Handle, alpm.alpm_pkg_get_licenses); - public ICollection Groups => EnumerableWrapper.Create(Handle, alpm.alpm_pkg_get_groups); - public ICollection Depends => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_depends); - public ICollection OptDepends => + public IEnumerable Groups => EnumerableWrapper.Create(Handle, alpm.alpm_pkg_get_groups); + public IEnumerable Depends => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_depends); + public IEnumerable OptDepends => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_optdepends); - public ICollection CheckDepends => + public IEnumerable CheckDepends => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_checkdepends); - public ICollection MakeDepends => + public IEnumerable MakeDepends => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_makedepends); - public ICollection Conflicts => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_conflicts); - public ICollection Provides => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_provides); - public ICollection Replaces => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_replaces); + public IEnumerable Conflicts => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_conflicts); + public IEnumerable Provides => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_provides); + public IEnumerable Replaces => EnumerableWrapper.CreateForDepend(Handle, alpm.alpm_pkg_get_replaces); public IReadOnlyList Files => new FileList(Handle, alpm.alpm_pkg_get_files(Handle)); - public ICollection Backup => EnumerableWrapper.CreateForBackup(Handle, alpm.alpm_pkg_get_backup); + public IEnumerable Backup => EnumerableWrapper.CreateForBackup(Handle, alpm.alpm_pkg_get_backup); public string Base64Signature => alpm.alpm_pkg_get_base64_sig(Handle); public ValidationType Validation => alpm.alpm_pkg_get_validation(Handle); public bool HasScriptlet => alpm.alpm_pkg_has_scriptlet(Handle); diff --git a/Alpm/alpm.cs b/Alpm/alpm.cs index 7db1c5c..bf20cce 100644 --- a/Alpm/alpm.cs +++ b/Alpm/alpm.cs @@ -251,6 +251,12 @@ namespace Foodsoft.Alpm [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8In))] string url); + [DllImport(nameof(alpm))] + public static extern int alpm_db_get_usage(SafeDatabaseHandle db, out Database.UsageFlags usage); + + [DllImport(nameof(alpm))] + public static extern int alpm_db_set_usage(SafeDatabaseHandle db, Database.UsageFlags usage); + [DllImport(nameof(alpm))] public static extern IntPtr alpm_pkg_get_pkg(SafeDatabaseHandle db, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8In))] diff --git a/Samples/Program.cs b/Samples/Program.cs index 49fe18b..2be67c5 100644 --- a/Samples/Program.cs +++ b/Samples/Program.cs @@ -31,7 +31,7 @@ namespace Samples using var h = new Handle("/", "/var/lib/pacman"); using var db = h.LocalDB; - foreach (var pkg in db.CachePackageCache) + foreach (var pkg in db.PackageCache) using (pkg) { Console.WriteLine($"Size: {pkg.DownloadSize}"); @@ -57,13 +57,10 @@ namespace Samples 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.CachePackageCache) - using (pkg) - { - Console.WriteLine("{0} {1} {2}", pkg.Name, pkg.Version, pkg.Description); - } + + using var pkg = db.PackageCache.FindSatisfier("gcc=9.3.0-1"); + Console.WriteLine($"{pkg?.Name} {pkg?.Version}"); return 0; }