From a8c62ab22d3953b47cee3da771b24526038c0a6e Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Thu, 22 Feb 2024 11:39:20 +0100 Subject: [PATCH 1/2] Alr.Commands.Search: change default behavior to include properties This patch comes from a comment of a user looking for gnatpp in Alire. gnatpp is part of the libabalang_tools crate and a 1.x `alr search gnatpp` returns nothing. The reason that by default only the release name and descriptions are searched. This is quite a bad user interaction. Here we change the default behavior to search in all properties of a release, including tags, executables, website, etc. We also display the list of properties that match the pattern. Searching in names and descriptions only is still possible with the --crates switch. --- src/alire/alire-releases.adb | 36 +++++ src/alire/alire-releases.ads | 5 + src/alr/alr-commands-search.adb | 203 +++++++++++++++------------ src/alr/alr-commands-search.ads | 3 - testsuite/tests/search/basic/test.py | 36 ++--- 5 files changed, 173 insertions(+), 110 deletions(-) diff --git a/src/alire/alire-releases.adb b/src/alire/alire-releases.adb index 2b80486e6..bf85b8c50 100644 --- a/src/alire/alire-releases.adb +++ b/src/alire/alire-releases.adb @@ -919,6 +919,42 @@ package body Alire.Releases is return False; end Property_Contains; + ----------------------- + -- Property_Contains -- + ----------------------- + + function Property_Contains (R : Release; Str : String) + return AAA.Strings.Vector + is + Results : AAA.Strings.Vector; + use AAA.Strings; + + Search : constant String := To_Lower_Case (Str); + begin + for P of Conditional.Enumerate (R.Properties) loop + declare + Image : constant String := P.Image; + begin + if Contains (Image, ":") then + declare + Prop : constant String := Head (Image, ':'); + Value : constant String := Trim (Tail (Image, ':')); + begin + if Contains (To_Lower_Case (Value), Search) then + Results.Append (Prop); + end if; + end; + else + if Contains (To_Lower_Case (Image), Search) then + Results.Append (Image); + end if; + end if; + end; + end loop; + + return Results; + end Property_Contains; + ------------------- -- From_Manifest -- ------------------- diff --git a/src/alire/alire-releases.ads b/src/alire/alire-releases.ads index f1552d627..6b3f2b2da 100644 --- a/src/alire/alire-releases.ads +++ b/src/alire/alire-releases.ads @@ -308,6 +308,11 @@ package Alire.Releases is function Property_Contains (R : Release; Str : String) return Boolean; -- True if some property contains the given string + function Property_Contains (R : Release; Str : String) + return AAA.Strings.Vector; + -- Return a vector with the names of propreties that contain the given + -- string. + function Satisfies (R : Release; Dep : Alire.Dependencies.Dependency'Class) return Boolean; diff --git a/src/alr/alr-commands-search.adb b/src/alr/alr-commands-search.adb index 71a36b24c..44d8b0136 100644 --- a/src/alr/alr-commands-search.adb +++ b/src/alr/alr-commands-search.adb @@ -32,54 +32,96 @@ package body Alr.Commands.Search is Flag_Unsolv : constant String := TTY.Error ("X"); Flag_External : constant String := TTY.Warn ("E"); - ------------------ - -- List_Release -- - ------------------ + ------------------- + -- Print_Release -- + ------------------- - procedure List_Release (R : Alire.Releases.Release) is + procedure Print_Release (R : Alire.Releases.Release; + Match_Locations : AAA.Strings.Vector) + is package Solver renames Alire.Solver; + begin Trace.Debug ("Listing release: " & R.Milestone.TTY_Image); - if (Cmd.Prop.all = "" - or else - R.Property_Contains (Cmd.Prop.all) - or else - AAA.Strings.Contains (R.Notes, Cmd.Prop.all) - or else - AAA.Strings.Contains (R.Description, - Cmd.Prop.all)) - and then - (Cmd.External or else not R.Origin.Is_System) - then - Found := Found + 1; - Tab.New_Row; - Tab.Append (Alire.Utils.TTY.Name (+R.Name)); - Tab.Append - ((if R.Origin.Is_System then Flag_System else " ") & - (if R.Is_Available (Platform.Properties) - then " " else Flag_Unav) & - (if R.Origin.Is_System then " " else - (if Solver.Is_Resolvable - (R.Dependencies (Platform.Properties), - Platform.Properties, - Alire.Solutions.Empty_Valid_Solution, - Options => (Age => Query_Policy, - On_Timeout => Solver.Stop, - others => <>)) - then " " - else Flag_Unsolv))); - Tab.Append (TTY.Version (Semantic_Versioning.Image (R.Version))); - Tab.Append (TTY.Description (R.Description)); - Tab.Append (R.Notes); + Found := Found + 1; + Tab.New_Row; + Tab.Append (Alire.Utils.TTY.Name (+R.Name)); + Tab.Append + ((if R.Origin.Is_System then Flag_System else " ") & + (if R.Is_Available (Platform.Properties) + then " " else Flag_Unav) & + (if R.Origin.Is_System then " " else + (if Solver.Is_Resolvable + (R.Dependencies (Platform.Properties), + Platform.Properties, + Alire.Solutions.Empty_Valid_Solution, + Options => (Age => Query_Policy, + On_Timeout => Solver.Stop, + others => <>)) + then " " + else Flag_Unsolv))); + Tab.Append (TTY.Version (Semantic_Versioning.Image (R.Version))); + Tab.Append (TTY.Description (R.Description)); + Tab.Append (R.Notes); + Tab.Append (Match_Locations.Flatten (", ")); + end Print_Release; + + ----------------- + -- Match_Crate -- + ----------------- + + function Match_Crate (Crate : Alire.Crates.Crate; + Pattern : String) + return AAA.Strings.Vector + is + Match_Locations : AAA.Strings.Vector; + begin + if AAA.Strings.Contains (+Crate.Name, Pattern) then + Match_Locations.Append ("Name"); end if; - end List_Release; - --------------------- - -- List_Undetected -- - --------------------- + if AAA.Strings.Contains (Crate.Description, Pattern) then + Match_Locations.Append ("Description"); + end if; + return Match_Locations; + end Match_Crate; + + -------------------- + -- Filter_Release -- + -------------------- - procedure List_Undetected (Name : Alire.Crate_Name; - Ext : Alire.Externals.External'Class) is + procedure Filter_Release (R : Alire.Releases.Release; + Pattern : String) + is + begin + Trace.Debug ("Listing release: " & R.Milestone.TTY_Image); + + if Pattern = "" then + -- Empty pattern means include everything + Print_Release (R, Match_Locations => AAA.Strings.Empty_Vector); + else + declare + Match_Locations : constant AAA.Strings.Vector + := R.Property_Contains (Pattern); + begin + if not Match_Locations.Is_Empty + and then + (Cmd.External or else not R.Origin.Is_System) + then + Print_Release (R, Match_Locations); + end if; + end; + end if; + end Filter_Release; + + -------------------- + -- Print_External -- + -------------------- + + procedure Print_External (Name : Alire.Crate_Name; + Ext : Alire.Externals.External'Class; + Match_Locations : AAA.Strings.Vector) + is begin Found := Found + 1; Tab.New_Row; @@ -90,7 +132,8 @@ package body Alr.Commands.Search is Tab.Append ("external"); Tab.Append (Alire.Index.Crate (Name).TTY_Description); Tab.Append (Ext.Image); - end List_Undetected; + Tab.Append (Match_Locations.Flatten (", ")); + end Print_External; begin @@ -103,7 +146,7 @@ package body Alr.Commands.Search is -- Search into crates if Alire.Utils.Count_True - ((Cmd.Detect, Cmd.External, Cmd.Full, Cmd.Prop.all /= "")) > 0 + ((Cmd.Detect, Cmd.External, Cmd.Full)) > 0 then Reportaise_Wrong_Arguments ("Extra switches are incompatible with --crates"); @@ -133,16 +176,14 @@ package body Alr.Commands.Search is if Args.Count = 0 and then not Cmd.List - and then - Cmd.Prop.all = "" then - -- no search term, nor --list, nor --prop + -- no search term, nor --list Reportaise_Wrong_Arguments - ("Please provide a search term, --property, or use" & + ("Please provide a search term, or use" & " --list to show all available releases"); end if; - if Args.Count = 0 and then Cmd.Prop.all /= "" then + if Args.Count = 0 then Cmd.List := True; end if; @@ -158,6 +199,7 @@ package body Alr.Commands.Search is Tab.Append (TTY.Bold ("VERSION")); Tab.Append (TTY.Bold ("DESCRIPTION")); Tab.Append (TTY.Bold ("NOTES")); + Tab.Append (TTY.Bold ("MATCHES")); declare Busy : Simple_Logging.Ongoing := @@ -167,8 +209,8 @@ package body Alr.Commands.Search is -- List_All_Or_Latest -- ------------------------ - procedure List_All_Or_Latest - (Crate : Alire.Crates.Crate) + procedure List_All_Or_Latest (Crate : Alire.Crates.Crate; + Pattern : String) is Progress : Trace.Ongoing := Trace.Activity (Crate.Name.Index_Prefix) @@ -176,11 +218,11 @@ package body Alr.Commands.Search is begin if Cmd.Full then for Release of reverse Crate.Releases loop - List_Release (Release); + Filter_Release (Release, Pattern); Busy.Step; end loop; elsif not Crate.Releases.Is_Empty then - List_Release (Crate.Releases.Last_Element); + Filter_Release (Crate.Releases.Last_Element, Pattern); Busy.Step; end if; end List_All_Or_Latest; @@ -189,20 +231,28 @@ package body Alr.Commands.Search is -- List_Externals -- -------------------- - procedure List_Externals (Crate : Alire.Crates.Crate) + procedure List_Externals (Crate : Alire.Crates.Crate; + Pattern : String) is Progress : Trace.Ongoing := Trace.Activity (Crate.Name.Index_Prefix) - with Unreferenced; + with Unreferenced; + + Match_Locations : constant AAA.Strings.Vector := + Match_Crate (Crate, Pattern); begin - if Cmd.External then + if Cmd.External + and then + (Pattern = "" or else not Match_Locations.Is_Empty) + then -- We must show only externals that have failed detection -- (otherwise they'll appear as normal releases with --detect). for External of Crate.Externals loop - if not Cmd.Detect or else - External.Detect (Crate.Name).Is_Empty + if not Cmd.Detect + or else + External.Detect (Crate.Name).Is_Empty then - List_Undetected (Crate.Name, External); + Print_External (Crate.Name, External, Match_Locations); end if; end loop; end if; @@ -212,14 +262,16 @@ package body Alr.Commands.Search is -- List_Crate -- ---------------- - procedure List_Crate (Crate : Alire.Crates.Crate) is + procedure List_Crate (Crate : Alire.Crates.Crate; + Pattern : String) + is begin if Cmd.Detect then Alire.Index.Detect_Externals (Crate.Name, Platform.Properties); end if; - List_All_Or_Latest (Crate); - List_Externals (Crate); + List_All_Or_Latest (Crate, Pattern); + List_Externals (Crate, Pattern); Busy.Step; end List_Crate; @@ -244,25 +296,10 @@ package body Alr.Commands.Search is Crate : Alire.Crates.Crate renames Element (I); Pattern : constant String := (if Cmd.List - then "" + then "" -- No filtering else To_Lower_Case (Args (1))); begin - if Cmd.List then - - -- List all releases - List_Crate (Crate); - - else - - -- Search into release names and descriptions - if Contains (To_Lower_Case (+Crate.Name), Pattern) - or else - Contains (To_Lower_Case (Crate.Description), Pattern) - then - List_Crate (Crate); - end if; - - end if; + List_Crate (Crate, Pattern); end; Next (I); @@ -285,8 +322,8 @@ package body Alr.Commands.Search is return AAA.Strings.Vector is (AAA.Strings.Empty_Vector - .Append ("Searches the given substring in crate names (or properties" - & " with --property), and shows the most recent release" + .Append ("Searches the given substring in crate names and properties," + & " and shows the most recent release" & " of matching crates (unless --full is specified).") .New_Line .Append ("Use --crates to get a simple list of only crate names and " @@ -346,12 +383,6 @@ package body Alr.Commands.Search is Cmd.External'Access, "", "--external", "Include externally-provided releases in search"); - - Define_Switch (Config, - Cmd.Prop'Access, - "", "--property=", - "Search TEXT in property values", - Argument => "TEXT"); end Setup_Switches; end Alr.Commands.Search; diff --git a/src/alr/alr-commands-search.ads b/src/alr/alr-commands-search.ads index 296131174..8e0e40ecd 100644 --- a/src/alr/alr-commands-search.ads +++ b/src/alr/alr-commands-search.ads @@ -1,7 +1,5 @@ with AAA.Strings; -private with GNAT.Strings; - package Alr.Commands.Search is type Command is new Commands.Command with private; @@ -38,7 +36,6 @@ private Full : aliased Boolean := False; List : aliased Boolean := False; External : aliased Boolean := False; - Prop : aliased GNAT.Strings.String_Access; end record; end Alr.Commands.Search; diff --git a/testsuite/tests/search/basic/test.py b/testsuite/tests/search/basic/test.py index 56f4fa629..815d96de3 100644 --- a/testsuite/tests/search/basic/test.py +++ b/testsuite/tests/search/basic/test.py @@ -6,13 +6,13 @@ from drivers.asserts import assert_eq -def format_line(name, status, version, description, notes): - return '{: <9} {: <7} {: <8} {: <54} {: <5}'.format( - name, status, version, description, notes).rstrip(' ') + '\n' +def format_line(name, status, version, description, notes, matches): + return '{: <9} {: <7} {: <8} {: <54} {: <6} {: <7}'.format( + name, status, version, description, notes, matches).rstrip(' ') + '\n' def format_table(*args): - lines = [format_line('NAME', 'STATUS', 'VERSION', 'DESCRIPTION', 'NOTES')] + lines = [format_line('NAME', 'STATUS', 'VERSION', 'DESCRIPTION', 'NOTES', "MATCHES")] for arg in args: lines.append(format_line(*arg)) return ''.join(lines) @@ -21,38 +21,32 @@ def format_table(*args): # List latest releases crates p = run_alr('search', '--list') assert_eq(format_table( - ('hello', '', '1.0.1', '"Hello, world!" demonstration project', ''), + ('hello', '', '1.0.1', '"Hello, world!" demonstration project', '', ''), ('libhello', '', '1.0.0', - '"Hello, world!" demonstration project support library', ''), + '"Hello, world!" demonstration project support library', '', ''), ), p.out) # List all releases crates p = run_alr('search', '--list', '--full') assert_eq(format_table( - ('hello', '', '1.0.1', '"Hello, world!" demonstration project', ''), - ('hello', '', '1.0.0', '"Hello, world!" demonstration project', ''), + ('hello', '', '1.0.1', '"Hello, world!" demonstration project', '', ''), + ('hello', '', '1.0.0', '"Hello, world!" demonstration project', '', ''), ('libhello', '', '1.0.0', - '"Hello, world!" demonstration project support library', ''), + '"Hello, world!" demonstration project support library', '', ''), ), p.out) -# Actually search in the index. First, on crate names/description -p = run_alr('search', 'lib') -assert_eq(format_table( - ('libhello', '', '1.0.0', - '"Hello, world!" demonstration project support library', ''), -), p.out) - -p = run_alr('search', 'libhello-tag1') -assert_eq('', p.out) +# Actually search in the index. First, on crate names +p = run_alr('search', '--crates', 'lib') +assert_eq('libhello "Hello, world!" demonstration project support library\n', p.out) -# Then on crate properties -p = run_alr('search', '--property', 'libhello-tag1') +# Then on all properties +p = run_alr('search', 'libhello-tag1') assert_eq(format_table( ('libhello', '', '1.0.0', - '"Hello, world!" demonstration project support library', ''), + '"Hello, world!" demonstration project support library', '', 'Tag'), ), p.out) print('SUCCESS') From 48df7c91dce30b375e3dcc9a20f1785997c14969 Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Thu, 22 Feb 2024 18:44:26 +0100 Subject: [PATCH 2/2] Alr.Commands.Search: use a set rather than a vector for matching props --- src/alire/alire-releases.adb | 8 +++--- src/alire/alire-releases.ads | 5 ++-- src/alr/alr-commands-search.adb | 28 +++++++++---------- .../li/libhello/libhello-1.0.0.toml | 4 ++- testsuite/tests/search/basic/test.py | 4 +-- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/alire/alire-releases.adb b/src/alire/alire-releases.adb index bf85b8c50..b944de4e8 100644 --- a/src/alire/alire-releases.adb +++ b/src/alire/alire-releases.adb @@ -924,9 +924,9 @@ package body Alire.Releases is ----------------------- function Property_Contains (R : Release; Str : String) - return AAA.Strings.Vector + return AAA.Strings.Set is - Results : AAA.Strings.Vector; + Results : AAA.Strings.Set; use AAA.Strings; Search : constant String := To_Lower_Case (Str); @@ -941,12 +941,12 @@ package body Alire.Releases is Value : constant String := Trim (Tail (Image, ':')); begin if Contains (To_Lower_Case (Value), Search) then - Results.Append (Prop); + Results.Include (Prop); end if; end; else if Contains (To_Lower_Case (Image), Search) then - Results.Append (Image); + Results.Include (Image); end if; end if; end; diff --git a/src/alire/alire-releases.ads b/src/alire/alire-releases.ads index 6b3f2b2da..bf679b7fe 100644 --- a/src/alire/alire-releases.ads +++ b/src/alire/alire-releases.ads @@ -309,9 +309,8 @@ package Alire.Releases is -- True if some property contains the given string function Property_Contains (R : Release; Str : String) - return AAA.Strings.Vector; - -- Return a vector with the names of propreties that contain the given - -- string. + return AAA.Strings.Set; + -- Return a set with the names of properties that contain the given string function Satisfies (R : Release; Dep : Alire.Dependencies.Dependency'Class) diff --git a/src/alr/alr-commands-search.adb b/src/alr/alr-commands-search.adb index 44d8b0136..f5ff17169 100644 --- a/src/alr/alr-commands-search.adb +++ b/src/alr/alr-commands-search.adb @@ -37,7 +37,7 @@ package body Alr.Commands.Search is ------------------- procedure Print_Release (R : Alire.Releases.Release; - Match_Locations : AAA.Strings.Vector) + Match_Locations : AAA.Strings.Set) is package Solver renames Alire.Solver; @@ -63,7 +63,7 @@ package body Alr.Commands.Search is Tab.Append (TTY.Version (Semantic_Versioning.Image (R.Version))); Tab.Append (TTY.Description (R.Description)); Tab.Append (R.Notes); - Tab.Append (Match_Locations.Flatten (", ")); + Tab.Append (Match_Locations.To_Vector.Flatten (", ")); end Print_Release; ----------------- @@ -72,16 +72,16 @@ package body Alr.Commands.Search is function Match_Crate (Crate : Alire.Crates.Crate; Pattern : String) - return AAA.Strings.Vector + return AAA.Strings.Set is - Match_Locations : AAA.Strings.Vector; + Match_Locations : AAA.Strings.Set; begin if AAA.Strings.Contains (+Crate.Name, Pattern) then - Match_Locations.Append ("Name"); + Match_Locations.Include ("Name"); end if; if AAA.Strings.Contains (Crate.Description, Pattern) then - Match_Locations.Append ("Description"); + Match_Locations.Include ("Description"); end if; return Match_Locations; end Match_Crate; @@ -90,7 +90,7 @@ package body Alr.Commands.Search is -- Filter_Release -- -------------------- - procedure Filter_Release (R : Alire.Releases.Release; + procedure Filter_Release (R : Alire.Releases.Release; Pattern : String) is begin @@ -98,10 +98,10 @@ package body Alr.Commands.Search is if Pattern = "" then -- Empty pattern means include everything - Print_Release (R, Match_Locations => AAA.Strings.Empty_Vector); + Print_Release (R, Match_Locations => AAA.Strings.Empty_Set); else declare - Match_Locations : constant AAA.Strings.Vector + Match_Locations : constant AAA.Strings.Set := R.Property_Contains (Pattern); begin if not Match_Locations.Is_Empty @@ -119,8 +119,8 @@ package body Alr.Commands.Search is -------------------- procedure Print_External (Name : Alire.Crate_Name; - Ext : Alire.Externals.External'Class; - Match_Locations : AAA.Strings.Vector) + Ext : Alire.Externals.External'Class; + Match_Locations : AAA.Strings.Set) is begin Found := Found + 1; @@ -132,7 +132,7 @@ package body Alr.Commands.Search is Tab.Append ("external"); Tab.Append (Alire.Index.Crate (Name).TTY_Description); Tab.Append (Ext.Image); - Tab.Append (Match_Locations.Flatten (", ")); + Tab.Append (Match_Locations.To_Vector.Flatten (", ")); end Print_External; begin @@ -209,7 +209,7 @@ package body Alr.Commands.Search is -- List_All_Or_Latest -- ------------------------ - procedure List_All_Or_Latest (Crate : Alire.Crates.Crate; + procedure List_All_Or_Latest (Crate : Alire.Crates.Crate; Pattern : String) is Progress : Trace.Ongoing := @@ -238,7 +238,7 @@ package body Alr.Commands.Search is Trace.Activity (Crate.Name.Index_Prefix) with Unreferenced; - Match_Locations : constant AAA.Strings.Vector := + Match_Locations : constant AAA.Strings.Set := Match_Crate (Crate, Pattern); begin if Cmd.External diff --git a/testsuite/fixtures/basic_index/li/libhello/libhello-1.0.0.toml b/testsuite/fixtures/basic_index/li/libhello/libhello-1.0.0.toml index c46f09fab..11d2c745e 100644 --- a/testsuite/fixtures/basic_index/li/libhello/libhello-1.0.0.toml +++ b/testsuite/fixtures/basic_index/li/libhello/libhello-1.0.0.toml @@ -3,7 +3,9 @@ name = "libhello" version = "1.0.0" maintainers = ["alejandro@mosteo.com"] maintainers-logins = ["mylogin"] -tags = ["libhello-tag1"] + +# for an `alr search` test we need multiple tags that match the same pattern +tags = ["libhello-tag1", "libhello-tag2"] [configuration.variables] Var1={type="Boolean", default=true} diff --git a/testsuite/tests/search/basic/test.py b/testsuite/tests/search/basic/test.py index 815d96de3..ab4deac3d 100644 --- a/testsuite/tests/search/basic/test.py +++ b/testsuite/tests/search/basic/test.py @@ -42,8 +42,8 @@ def format_table(*args): assert_eq('libhello "Hello, world!" demonstration project support library\n', p.out) -# Then on all properties -p = run_alr('search', 'libhello-tag1') +# Then on all properties, matching properties name should appear only once +p = run_alr('search', 'libhello-tag') assert_eq(format_table( ('libhello', '', '1.0.0', '"Hello, world!" demonstration project support library', '', 'Tag'),