From cce020a5078c6158f0c20b12807270b7c32858eb Mon Sep 17 00:00:00 2001 From: Alejandro R Mosteo Date: Wed, 20 Jul 2022 12:52:54 +0200 Subject: [PATCH] Lazy index loading (2/2) (#1086) * Index queries autoload crates if required * Avoid infinite recursion when no indexes configured * Remove references to Requires_Full_Index * Fixed issues pending "provides" redo * Generate and use a providers cache file This cache file, which is common to all indexes, tells us in advance which crates have to be loaded because they provide some another crate. E.g., if "gnat" is requested to be loaded, we need to load all gnat_native, and x-compilers. If this file doesn't exist, we can only be sure by loading the full index, at which time the file is regenerated for future use. * Fix bug where all crates with same prefix were loaded E.g. we were loading all gn* when only gnat_native needed to be loaded * Fix providers generation when no index configured * Add spinner during index load * Remove the now redundant external aliases collection * Removed last instances of forced index loading * Fix for older compilers * Test for the generated metadata file * publishing.md: note about private indexes and "provides" * Post-merge fix Co-authored-by: GHA --- doc/publishing.md | 15 ++ src/alire/alire-containers.ads | 2 +- src/alire/alire-crates.adb | 9 +- src/alire/alire-index.adb | 160 ++++++++++++------ src/alire/alire-index.ads | 18 +- src/alire/alire-index_on_disk-loading.adb | 157 +++++++++++++++++ src/alire/alire-index_on_disk.ads | 2 +- src/alire/alire-provides.adb | 52 ++++++ src/alire/alire-provides.ads | 29 ++++ src/alire/alire-shared.adb | 3 +- src/alire/alire-solver.adb | 2 - src/alire/alire-toml_index.adb | 4 +- src/alr/alr-commands-show.adb | 2 - .../my_index/index/cr/crate/crate-1.0.0.toml | 11 ++ .../metadata/my_index/index/index.toml | 1 + testsuite/tests/provides/metadata/test.py | 34 ++++ testsuite/tests/provides/metadata/test.yaml | 4 + 17 files changed, 432 insertions(+), 73 deletions(-) create mode 100644 testsuite/tests/provides/metadata/my_index/index/cr/crate/crate-1.0.0.toml create mode 100644 testsuite/tests/provides/metadata/my_index/index/index.toml create mode 100644 testsuite/tests/provides/metadata/test.py create mode 100644 testsuite/tests/provides/metadata/test.yaml diff --git a/doc/publishing.md b/doc/publishing.md index 5c7f6445..b8c86f3f 100644 --- a/doc/publishing.md +++ b/doc/publishing.md @@ -265,3 +265,18 @@ Here's an example: This will be shown as: [![Alire](https://img.shields.io/endpoint?url=https://alire.ada.dev/badges/hal.json)](https://alire.ada.dev/crates/hal.html) + +## Publishing to a local/private index + +Having a local index may be useful sometimes, be it for local testing, or for +private crates not intended for publication. + +There is no practical difference between the community index that is cloned +locally and a private local index stored on disk. Hence, after obtaining the +manifest file with `alr publish`, it is a matter of placing it at the expected +location within the index: `/path/to/index/cr/crate_name/crate_name-x.x.x.toml` + +If the crate being published locally contains `"provides"` definitions, it is +necessary to call `alr index --update-all` once to ensure it is properly used +by the dependency solver. This is only necessary for the first release in a +crate that uses the `"provides"` feature. diff --git a/src/alire/alire-containers.ads b/src/alire/alire-containers.ads index af78037d..c5fb835e 100644 --- a/src/alire/alire-containers.ads +++ b/src/alire/alire-containers.ads @@ -1,6 +1,6 @@ with Ada.Containers.Indefinite_Ordered_Sets; -package Alire.Containers is +package Alire.Containers with Preelaborate is package Crate_Name_Sets is new Ada.Containers.Indefinite_Ordered_Sets (Crate_Name); diff --git a/src/alire/alire-crates.adb b/src/alire/alire-crates.adb index 4701af77..aefce46d 100644 --- a/src/alire/alire-crates.adb +++ b/src/alire/alire-crates.adb @@ -134,15 +134,12 @@ package body Alire.Crates is end if; -- Register any aliased in the detectors for this crate, so we - -- know when to detect. Also the trivial equivalence, for the - -- benefit of queries in the index. - - Index.Register_External_Alias (This.Name, This.Name); + -- know when to detect. for Detector of This.Externals.Detectors loop for Alias of Detector.Equivalences loop - Index.Register_External_Alias (Provider => This.Name, - Providing => Alias); + Index.Register_Alias (Provider => This.Name, + Providing => Alias); end loop; end loop; end if; diff --git a/src/alire/alire-index.adb b/src/alire/alire-index.adb index ed08ac2c..dbdba8a3 100644 --- a/src/alire/alire-index.adb +++ b/src/alire/alire-index.adb @@ -3,7 +3,6 @@ with Ada.Containers.Indefinite_Ordered_Sets; with Alire.Containers; with Alire.Index_On_Disk.Loading; - with Alire.Utils.TTY; package body Alire.Index is @@ -16,27 +15,22 @@ package body Alire.Index is "<", Releases.Containers."="); subtype Release_Alias_Map is Release_Set_Maps.Map; - package External_Alias_Maps is new - Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, - Containers.Crate_Name_Sets.Set, - "<", - Containers.Crate_Name_Sets."="); - subtype External_Alias_Map is External_Alias_Maps.Map; - use all type Semantic_Versioning.Version; Contents : aliased Alire.Crates.Containers.Maps.Map; -- Regular mapping from crate name to its releases - Aliases : Release_Alias_Map; + Release_Aliases : Release_Alias_Map; -- Mapping from crate name to any release that satisfies it. Currently, -- releases are duplicated in memory. These two collections could be made -- to share releases via some indirection or pointers. - External_Aliases : External_Alias_Map; - -- For external crates that provide another crate, we need to be aware - -- when external detection is requested. This mapping goes in the direction - -- Provided -> Providers. + Crate_Aliases : aliased Provides.Crate_Provider_Map; + -- During on-demand crate loading, we need to know which crates also + -- provide the requested crate. This information is redundant with + -- Release_Aliases, but as this simpler information is the one that's + -- read/written to disk on index update, we better keep a separate copy + -- for simplicity. --------- -- Add -- @@ -90,12 +84,24 @@ package body Alire.Index is for Mil of Release.Provides loop declare Crate : Releases.Containers.Release_Set := - (if Aliases.Contains (Mil.Crate) - then Aliases (Mil.Crate) + (if Release_Aliases.Contains (Mil.Crate) + then Release_Aliases (Mil.Crate) else Releases.Containers.Empty_Release_Set); + + Providers : Provides.Crate_Providers := + (if Crate_Aliases.Contains (Mil.Crate) + then Crate_Aliases (Mil.Crate) + else Containers.Crate_Name_Sets.Empty_Set); begin + -- Add release-level aliases + Crate.Include (Release); - Aliases.Include (Mil.Crate, Crate); + Release_Aliases.Include (Mil.Crate, Crate); + + -- Add crate-level aliases + + Providers.Include (Release.Name); + Crate_Aliases.Include (Mil.Crate, Providers); end; end loop; end Add_Aliases; @@ -108,19 +114,6 @@ package body Alire.Index is Add_Aliases; end Add; - -------------------------- - -- Detect_All_Externals -- - -------------------------- - - procedure Detect_All_Externals (Env : Properties.Vector) is - begin - Trace.Detail ("Detecting external releases..."); - - for Crate of Contents loop - Detect_Externals (Crate.Name, Env); - end loop; - end Detect_All_Externals; - package Name_Sets is new Ada.Containers.Indefinite_Ordered_Sets (Crate_Name); Already_Detected : Name_Sets.Set; @@ -131,25 +124,52 @@ package body Alire.Index is procedure Detect_Externals (Name : Crate_Name; Env : Properties.Vector) is begin + Index_Loading.Load (Name, + Detect_Externals => False, + Strict => False); + -- We don't ask to detect because we are going to do it right after, and + -- this breaks a potential infinite recursion. + if Already_Detected.Contains (Name) then Trace.Debug ("Not redoing detection of externals for crate " & (+Name)); - elsif not External_Aliases.Contains (Name) then + elsif not Has_Externals (Name) then Trace.Debug ("Skipping detection for crate without externals: " & Utils.TTY.Name (Name)); else Already_Detected.Insert (Name); Trace.Debug ("Looking for externals for crate: " & (+Name)); - for Provider of External_Aliases (Name) loop - Trace.Debug ("Detecting via provider " & - Utils.TTY.Name (Provider)); - for Release of Contents (Provider).Externals.Detect (Provider, Env) - loop - Trace.Debug ("Adding external: " & Release.Milestone.Image); - Add (Release); + declare + Providers : Provides.Crate_Providers := + (if Crate_Aliases.Contains (Name) + then Crate_Aliases (Name) + else Containers.Crate_Name_Sets.Empty_Set); + -- This copy is needed to avoid tampering with collections if a + -- new alias were found during detection. + begin + Providers.Include (Name); + -- Always use the crate itself to look for externals + + for Provider of Providers loop + if Contents.Contains (Provider) then + -- It may not exist if this is a virtual crate without + -- releases or detectors. + + if not Contents (Provider).Externals.Is_Empty then + Trace.Debug ("Detecting via provider: " & + Utils.TTY.Name (Provider)); + end if; + for Release of Contents (Provider).Externals + .Detect (Provider, Env) + loop + Trace.Debug ("Adding external: " + & Release.Milestone.Image); + Add (Release); + end loop; + end if; end loop; - end loop; + end; end if; end Detect_Externals; @@ -167,6 +187,13 @@ package body Alire.Index is return Contents'Access; end All_Crates; + ----------------------- + -- All_Crate_Aliases -- + ----------------------- + + function All_Crate_Aliases return access Provides.Crate_Provider_Map + is (Crate_Aliases'Access); + ----------- -- Crate -- ----------- @@ -264,24 +291,55 @@ package body Alire.Index is ------------------- function Has_Externals (Name : Crate_Name) return Boolean - is (External_Aliases.Contains (Name)); + is + begin + Index_Loading.Load (Name, Detect_Externals => False, Strict => False); - ----------------------------- - -- Register_External_Alias -- - ----------------------------- + -- Detectors in the crate itself + + if Contents.Contains (Name) and then + not Contents (Name).Externals.Is_Empty + then + return True; + end if; - procedure Register_External_Alias (Provider : Crate_Name; - Providing : Crate_Name) + -- Detectors in other crates that provide it (regular or external) + + if Crate_Aliases.Contains (Name) then + for Provider of Crate_Aliases (Name) loop + if Contents.Contains (Provider) and then + not Contents (Provider).Externals.Is_Empty + then + return True; + end if; + end loop; + end if; + + return False; + end Has_Externals; + + -------------------- + -- Register_Alias -- + -------------------- + + procedure Register_Alias (Provider : Crate_Name; + Providing : Crate_Name) is begin - if External_Aliases.Contains (Providing) then - External_Aliases (Providing).Include (Provider); + if Provider = Providing then + return; + -- We don't want the trivial equivalence here as this pollutes the + -- written file too much. + end if; + + if Crate_Aliases.Contains (Providing) then + Crate_Aliases (Providing).Include (Provider); else - External_Aliases.Insert + Crate_Aliases.Insert (Providing, Containers.Crate_Name_Sets.To_Set (Provider)); end if; - end Register_External_Alias; + end Register_Alias; ------------------- -- Release_Count -- @@ -326,10 +384,10 @@ package body Alire.Index is end loop; end if; - -- And any aliases via Provides + -- And any Release_Aliases via Provides - if Use_Equivalences and then Aliases.Contains (Dep.Crate) then - for Release of Aliases (Dep.Crate) loop + if Use_Equivalences and then Release_Aliases.Contains (Dep.Crate) then + for Release of Release_Aliases (Dep.Crate) loop if With_Origin (Release.Origin.Kind) and then Release.Satisfies (Dep) and then (not Available_Only or else Release.Is_Available (Env)) diff --git a/src/alire/alire-index.ads b/src/alire/alire-index.ads index dfcec4d6..a4f29af0 100644 --- a/src/alire/alire-index.ads +++ b/src/alire/alire-index.ads @@ -6,6 +6,7 @@ with Alire.Dependencies; with Alire.Origins; with Alire.Policies; with Alire.Properties; +with Alire.Provides; with Alire.Releases.Containers; with Semantic_Versioning.Extended; @@ -77,17 +78,14 @@ package Alire.Index is Policy : Policies.For_Index_Merging := Policies.Merge_Priorizing_Existing); - procedure Detect_All_Externals (Env : Properties.Vector); - -- Goes over the list of crates and applies external detection, indexing - -- any found externals. This has effect only the first time it is called. - procedure Detect_Externals (Name : Crate_Name; Env : Properties.Vector); -- Add only the externals of this crate. This has effect only the first -- time it is called for a crate. - procedure Register_External_Alias (Provider : Crate_Name; - Providing : Crate_Name); - -- Register that Provider has external detectors for Providing + procedure Register_Alias (Provider : Crate_Name; + Providing : Crate_Name); + -- Register that Provider has external detectors for Providing, or simply + -- it is a regular release that provides Providing. --------------------- -- BASIC QUERIES -- @@ -97,7 +95,10 @@ package Alire.Index is type Query_Options is record Detect_Externals : Boolean := False; + -- Whether to trigger external detection, which may be slow in some OSes + Load_From_Disk : Boolean := True; + -- Whether to rely on in-memory info, or load required crates on-demand end record; Query_Defaults : constant Query_Options := (others => <>); @@ -149,4 +150,7 @@ package Alire.Index is function All_Crates (Opts : Query_Options := Query_Defaults) return access constant Crates.Containers.Maps.Map; + function All_Crate_Aliases return access Provides.Crate_Provider_Map; + -- For use from the loading functions; not intended for normal clients + end Alire.Index; diff --git a/src/alire/alire-index_on_disk-loading.adb b/src/alire/alire-index_on_disk-loading.adb index 6092d082..289cf7ea 100644 --- a/src/alire/alire-index_on_disk-loading.adb +++ b/src/alire/alire-index_on_disk-loading.adb @@ -1,9 +1,12 @@ with Ada.Directories; +with Ada.Text_IO; with Alire.Config.Edit; with Alire.Containers; with Alire.Index; with Alire.Platforms.Current; +with Alire.Provides; +with Alire.TOML_Adapters; with Alire.Utils.TTY; with Alire.Warnings; @@ -23,6 +26,9 @@ package body Alire.Index_On_Disk.Loading is Indexes_Loaded : AAA.Strings.Set; -- Likewise, to avoid fully reloading of indexes + Providers_Loaded : Boolean := False; + -- Providers for all indexes are loaded the first time any crate is loaded + Cached_Set : Set; -- Likewise, avoid detecting time and again the same indexes @@ -31,6 +37,22 @@ package body Alire.Index_On_Disk.Loading is function Load_Index_Metadata (File : String; Value : out TOML.TOML_Value) return Outcome; + function Providers_File (Indexes_Dir : Any_Path) return Any_Path + is (Indexes_Dir / "providers.toml"); + + procedure Load_Providers (Indexes_Dir : Any_Path; Strict : Boolean); + -- Load crate providers for all indexes (unless already loaded). If this + -- metadata file doesn't exist, a full index load will be triggered and + -- the file will be rebuilt. + + procedure Invalidate_Providers (Indexes_Dir : Any_Path); + -- Whenever an index is added or updated, we must invalidate the cache on + -- disk containing crate virtual providers. + + procedure Save_Providers (Indexes_Dir : Any_Path); + -- Write to disk the providers info already in memory (generated after a + -- full load). + --------- -- Add -- --------- @@ -154,6 +176,9 @@ package body Alire.Index_On_Disk.Loading is Cached_Set.Clear; -- Reset cache so next detection finds the new index + Invalidate_Providers (Under); + -- Force reloading of crate aliases on next crate load + return Index.Add_With_Metadata; end; end Add; @@ -381,6 +406,12 @@ package body Alire.Index_On_Disk.Loading is elsif Path /= "" then Setup (Path); + Load_Providers (Path, Strict); + -- We can load at this point the common cached providers info for all + -- indexes at their containing dir. If this info does not exist, it + -- will be rebuilt via a full index load and the next call to Load + -- will find the crate already loaded. + declare Result : Outcome; Indexes : constant Set := Find_All (Path, Result); @@ -392,6 +423,7 @@ package body Alire.Index_On_Disk.Loading is end if; Load (Crate, Detect_Externals, Strict, Indexes, Path => ""); + return; end; end if; @@ -406,6 +438,27 @@ package body Alire.Index_On_Disk.Loading is for Index of From loop Index.Load (Crate, Strict); + + -- Load also all crates that provide the one being requested + + if Alire.Index.All_Crate_Aliases.Contains (Crate) then + declare + Providers : constant Provides.Crate_Providers := + Alire.Index.All_Crate_Aliases.all (Crate); + -- This copy is needed because the loading itself may result in + -- modifications to the collection we are iterating over, which + -- results in a tampering check (actually an Adjust exception). + begin + for Provider of Providers loop + if Provider /= Crate then + Trace.Debug ("Loading provider crate " + & Provider.As_String + & " for crate " & Crate.As_String); + Index.Load (Provider, Strict); + end if; + end loop; + end; + end if; end loop; -- Deal with externals after their detectors are loaded @@ -425,6 +478,8 @@ package body Alire.Index_On_Disk.Loading is Force : Boolean := False) return Outcome is + Spinner : Simple_Logging.Ongoing := + Simple_Logging.Activity ("Loading indexes"); begin Setup (From); @@ -437,6 +492,7 @@ package body Alire.Index_On_Disk.Loading is end if; for Index of Indexes loop + Spinner.Step ("Loading indexes [" & Index.Name & "]"); if Force or else not Indexes_Loaded.Contains (Index.Name) then declare Result : constant Outcome := Index.Load (Strict); @@ -449,6 +505,7 @@ package body Alire.Index_On_Disk.Loading is Indexes_Loaded.Include (Index.Name); end if; end loop; + Spinner.Step ("Loading indexes"); -- Mark all existing crates as already loaded @@ -456,6 +513,11 @@ package body Alire.Index_On_Disk.Loading is loop Crates_Loaded.Include (Crate.Name); end loop; + Spinner.Step; + + -- Save providers, that must be now up to date after a full loading + + Save_Providers (From); return Outcome_Success; end; @@ -479,6 +541,94 @@ package body Alire.Index_On_Disk.Loading is end if; end Load_Index_Metadata; + -------------------- + -- Load_Providers -- + -------------------- + + procedure Load_Providers (Indexes_Dir : Any_Path; Strict : Boolean) is + Filename : constant Any_Path := Providers_File (Indexes_Dir); + begin + if Providers_Loaded then + return; + end if; + + if not Ada.Directories.Exists (Filename) then + Load_All (From => Indexes_Dir, + Strict => Strict, + Force => True).Assert; + return; + end if; + + declare + Load_Result : constant TOML.Read_Result := + TOML.File_IO.Load_File (Filename); + begin + if not Load_Result.Success then + Trace.Warning ("Corrupted index providers file found at: " + & Filename & "; recreating it..."); + Trace.Debug ("Load error is: " & TOML.Format_Error (Load_Result)); + Ada.Directories.Delete_File (Filename); + Load_Providers (Indexes_Dir, Strict); + return; + end if; + + Alire.Index.All_Crate_Aliases.all := + Provides.From_TOML + (TOML_Adapters.From + (Load_Result.Value, + Context => "Loading index providers from " & Filename)); + + Providers_Loaded := True; + end; + end Load_Providers; + + -------------------------- + -- Invalidate_Providers -- + -------------------------- + + procedure Invalidate_Providers (Indexes_Dir : Any_Path) is + use Ada.Directories; + begin + Alire.Index.All_Crate_Aliases.Clear; + Providers_Loaded := False; + if Exists (Providers_File (Indexes_Dir)) then + Delete_File (Providers_File (Indexes_Dir)); + Trace.Debug ("dropped cache of crate aliases at " + & Providers_File (Indexes_Dir)); + end if; + end Invalidate_Providers; + + -------------------- + -- Save_Providers -- + -------------------- + + procedure Save_Providers (Indexes_Dir : Any_Path) is + use Ada.Directories; + use Ada.Text_IO; + File : File_Type; + Filename : constant Any_Path := Providers_File (Indexes_Dir); + begin + if not GNAT.OS_Lib.Is_Directory (Containing_Directory (Filename)) then + Trace.Debug ("Skipping saving of providers, as no indexes directory " + & "exists yet, so there are no possible providers"); + return; + end if; + + Create (File, Out_File, Filename); + TOML.File_IO.Dump_To_File (Alire.Index.All_Crate_Aliases.To_TOML, File); + Close (File); + exception + when E : others => + -- E.g., on disk full + Log_Exception (E); + if Is_Open (File) then + Close (File); + end if; + if GNAT.OS_Lib.Is_Regular_File (Filename) then + Ada.Directories.Delete_File (Filename); + end if; + end Save_Providers; + ---------------- -- Update_All -- ---------------- @@ -491,6 +641,13 @@ package body Alire.Index_On_Disk.Loading is return Result; end if; + -- First, invalidate providers metadata as this may change with the + -- update. + + Invalidate_Providers (Under); + + -- Now update normally + for Index of Indexes loop declare Result : constant Outcome := Index.Update; diff --git a/src/alire/alire-index_on_disk.ads b/src/alire/alire-index_on_disk.ads index 9928857d..1b2dd32f 100644 --- a/src/alire/alire-index_on_disk.ads +++ b/src/alire/alire-index_on_disk.ads @@ -48,7 +48,7 @@ package Alire.Index_On_Disk is Parent : Any_Path; Result : out Outcome) return Index'Class with Pre => From.Kind in TOML.TOML_Table; - -- Load from a output Index.To_TOML value + -- Load from an output Index.To_TOML value function New_Handler (Origin : URL; Name : Restricted_Name; diff --git a/src/alire/alire-provides.adb b/src/alire/alire-provides.adb index d2835a92..0359666a 100644 --- a/src/alire/alire-provides.adb +++ b/src/alire/alire-provides.adb @@ -74,4 +74,56 @@ package body Alire.Provides is return Result; end To_TOML; + --------------- + -- From_TOML -- + --------------- + + function From_TOML (From : TOML_Adapters.Key_Queue) + return Crate_Provider_Map + is + begin + return Result : Crate_Provider_Map do + loop + declare + Val : TOML.TOML_Value; + Key : constant String := From.Pop (Val); + Set : Containers.Crate_Name_Sets.Set; + begin + exit when Key = ""; + From.Assert (Val.Kind in TOML.TOML_Array, + "expected array of strings but got: " + & Val.Kind'Image); + for I in 1 .. Val.Length loop + Set.Insert (+Val.Item (I).As_String); + end loop; + + Result.Insert (+Key, Set); -- Store Provided --> Providers + end; + end loop; + end return; + end From_TOML; + + ------------- + -- To_TOML -- + ------------- + + function To_TOML (This : Crate_Provider_Map) return TOML.TOML_Value is + use Crate_Providers_Maps; + begin + return Result : constant TOML.TOML_Value := TOML.Create_Table do + for I in This.Iterate loop + declare + Val : constant TOML.TOML_Value := TOML.Create_Array; + -- A crate name array + begin + for Provider of This (I) loop + Val.Append (TOML.Create_String (Provider.As_String)); + end loop; + + Result.Set (Key (I).As_String, Val); + end; + end loop; + end return; + end To_TOML; + end Alire.Provides; diff --git a/src/alire/alire-provides.ads b/src/alire/alire-provides.ads index b8fe425d..a1bcde59 100644 --- a/src/alire/alire-provides.ads +++ b/src/alire/alire-provides.ads @@ -1,3 +1,6 @@ +with Ada.Containers.Indefinite_Ordered_Maps; + +with Alire.Containers; with Alire.Dependencies; with Alire.Milestones.Containers; with Alire.TOML_Adapters; @@ -29,6 +32,32 @@ package Alire.Provides with Preelaborate is function To_TOML (This : Equivalences) return TOML.TOML_Value with Post => To_TOML'Result.Kind in TOML.TOML_Array; + -- For lazy on-demand index load, we need to know which crate may be + -- fulfilled by another one. We could go even more fine grained and load + -- only specific releases, but as of right now index loading is granular + -- per crate, we only use a [provided crate] -> [provider crates] map. + -- Likewise, we could have a mapping per index, but we aren't making + -- this distinction per crate either. + + subtype Crate_Providers is Containers.Crate_Name_Sets.Set; + + package Crate_Providers_Maps is new + Ada.Containers.Indefinite_Ordered_Maps (Crate_Name, + Crate_Providers, + "<", + Containers.Crate_Name_Sets."="); + type Crate_Provider_Map is new Crate_Providers_Maps.Map with null record; + + function From_TOML (From : TOML_Adapters.Key_Queue) + return Crate_Provider_Map + with Pre => From.Unwrap.Kind in TOML.TOML_Table; + -- Expects a table containing entries like crate = ["crate1", "crate2"], + -- So elements are string -> array of string + + function To_TOML (This : Crate_Provider_Map) return TOML.TOML_Value with + Post => To_TOML'Result.Kind in TOML.TOML_Table; + -- See From_TOML for the generated format + private No_Equivalences : constant Equivalences := diff --git a/src/alire/alire-shared.adb b/src/alire/alire-shared.adb index 4eb5f580..fa8c98ea 100644 --- a/src/alire/alire-shared.adb +++ b/src/alire/alire-shared.adb @@ -68,8 +68,9 @@ package body Alire.Shared is -- Include external toolchain members if Detect_Externals then - Index.Detect_Externals (GNAT_External_Crate, + Index.Detect_Externals (GNAT_Crate, Root.Platform_Properties); + -- Will work via provides for any crate that provides a gnat compiler end if; for Tool of Toolchains.Tools loop diff --git a/src/alire/alire-solver.adb b/src/alire/alire-solver.adb index ac9206a4..d5c4a6d1 100644 --- a/src/alire/alire-solver.adb +++ b/src/alire/alire-solver.adb @@ -1084,8 +1084,6 @@ package body Alire.Solver is begin Index_On_Disk.Loading.Load_All.Assert; - Index.Detect_All_Externals (Props); - -- We need these two temporarily as "provides" still don't work 100% Trace.Detail ("Solving dependencies with options: " & Image (Options)); diff --git a/src/alire/alire-toml_index.adb b/src/alire/alire-toml_index.adb index c6a225c1..56bfd0c8 100644 --- a/src/alire/alire-toml_index.adb +++ b/src/alire/alire-toml_index.adb @@ -325,14 +325,14 @@ package body Alire.TOML_Index is Root : constant Any_Path := Locate_Root (Index, Result); -- Locate a dir containing a 'index.toml' metadata file inside the repo. -- This is the directory containing the actual crates. - Crate_Root : constant Any_Path := Root / Crate.Index_Prefix; + Crate_Root : constant Any_Path := Root / Crate.Index_Prefix / (+Crate); begin Result.Assert; TOML_Index.Strict := Load.Strict; Trace.Debug ("Loading single crate " & Utils.TTY.Name (Crate) - & " from " & Root); + & " from " & Crate_Root); if GNAT.OS_Lib.Is_Directory (Crate_Root) then Alire.Directories.Traverse_Tree diff --git a/src/alr/alr-commands-show.adb b/src/alr/alr-commands-show.adb index 9a15c2b4..b43c713c 100644 --- a/src/alr/alr-commands-show.adb +++ b/src/alr/alr-commands-show.adb @@ -72,8 +72,6 @@ package body Alr.Commands.Show is end if; if Cmd.Graph or else Cmd.Solve or else Cmd.Tree then - Cmd.Requires_Full_Index (Force_Reload => True); - declare Needed : constant Query.Solution := (if Current diff --git a/testsuite/tests/provides/metadata/my_index/index/cr/crate/crate-1.0.0.toml b/testsuite/tests/provides/metadata/my_index/index/cr/crate/crate-1.0.0.toml new file mode 100644 index 00000000..06f65644 --- /dev/null +++ b/testsuite/tests/provides/metadata/my_index/index/cr/crate/crate-1.0.0.toml @@ -0,0 +1,11 @@ +description = "Sample crate" +name = "crate" +version = "1.0.0" +licenses = [] +maintainers = ["any@bo.dy"] +maintainers-logins = ["someone"] + +provides = ["aliased=1.0"] + +[origin] +url = "file:." diff --git a/testsuite/tests/provides/metadata/my_index/index/index.toml b/testsuite/tests/provides/metadata/my_index/index/index.toml new file mode 100644 index 00000000..c2a2c7db --- /dev/null +++ b/testsuite/tests/provides/metadata/my_index/index/index.toml @@ -0,0 +1 @@ +version = "1.2" diff --git a/testsuite/tests/provides/metadata/test.py b/testsuite/tests/provides/metadata/test.py new file mode 100644 index 00000000..e82c28a1 --- /dev/null +++ b/testsuite/tests/provides/metadata/test.py @@ -0,0 +1,34 @@ +""" +Test the creation of the metadata file containing crate aliases (provides.toml) +""" + +import os + +from drivers.alr import run_alr +from drivers.asserts import assert_eq, assert_match + +aliases_file = os.path.join(os.environ['ALR_CONFIG'], + "indexes", "providers.toml") +# This is the file where crate aliases are stored + +# Initially, the file mustn't exist +assert not os.path.isfile(aliases_file), f"Unexpected file: {aliases_file}" + +# Force reading of the full index +run_alr("search", "--crates") + +# Now, the file must exist +assert os.path.isfile(aliases_file), f"Missing file: {aliases_file}" + +# Let's verify its contents +with open(aliases_file, "rt") as file: + contents = file.readlines() + +contents = "".join(contents).replace("\n", "") + +assert_eq('aliased = ["crate",]', + contents) +# This means that "crate" provides "aliased", so when solving "aliased" we also +# need to load "crate" + +print('SUCCESS') diff --git a/testsuite/tests/provides/metadata/test.yaml b/testsuite/tests/provides/metadata/test.yaml new file mode 100644 index 00000000..0a859639 --- /dev/null +++ b/testsuite/tests/provides/metadata/test.yaml @@ -0,0 +1,4 @@ +driver: python-script +indexes: + my_index: + in_fixtures: false -- 2.39.5