using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; 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; } // FIXME: This is "bug correct", but probably dumb to do it this way, instead just call add_server // like all the stuff in handle. // Also this stupid thing leaks the duped strings on failure. public IEnumerable Servers { get => EnumerableWrapper.Create(_handle, alpm.alpm_db_get_servers); set { var listPtr = IntPtr.Zero; var success = false; var err = 0; RuntimeHelpers.PrepareConstrainedRegions(); try { // 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); 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); } } public string Name => alpm.alpm_db_get_name(_handle); 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 CachePackageList PackageCache { get { var listPtr = alpm.alpm_db_get_pkgcache(_handle); if (listPtr == IntPtr.Zero) throw new AlpmException(_handle.SafeAlpmHandle); return new CachePackageList(listPtr, _handle, this); } } public UsageFlags Usage { get => Detail.WrapErrorOut(_handle.SafeAlpmHandle, _handle, alpm.alpm_db_get_usage); set => Detail.WrapErrorIn(_handle.SafeAlpmHandle, _handle, value, alpm.alpm_db_set_usage); } public void Dispose() { _handle.Dispose(); } public void Unregister() { _handle.Close(); } public void AddServer(string url) { Detail.WrapError(_handle.SafeAlpmHandle, () => alpm.alpm_db_add_server(_handle, url)); } public bool RemoveServer(string url) { return Detail.WrapErrorBool(_handle.SafeAlpmHandle, () => alpm.alpm_db_remove_server(_handle, url)); } public bool Update(bool force = false) { var err = alpm.alpm_db_update(force ? 1 : 0, _handle); if (err < 0) throw new AlpmException(_handle.SafeAlpmHandle); return err == 0; } public Package? GetPackage(string name) { var pkgPtr = alpm.alpm_pkg_get_pkg(_handle, name); if (pkgPtr == IntPtr.Zero) { var err = alpm.alpm_errno(_handle.SafeAlpmHandle); if (err == Error.PkgNotFound) return null; throw new AlpmException(err); } return new CachePackage(new SafeCachePackageHandle(pkgPtr, _handle), this); } [PrePrepareMethod] [SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")] public CachePackageList Search(IEnumerable needles) { var result = Detail.UseStringList(needles, listPtr => alpm.alpm_db_search(_handle, listPtr)); if (result == IntPtr.Zero) { var errNo = alpm.alpm_errno(_handle.SafeAlpmHandle); if (errNo != Error.OK) throw new AlpmException(errNo); } return new CachePackageList(result, _handle, this); } } }