From 40c25f1e1ad0a8dd36558ed442add1d984c7d539 Mon Sep 17 00:00:00 2001 From: Alejandro R Mosteo Date: Fri, 24 Feb 2023 12:54:34 +0100 Subject: [PATCH] New `--nested` switch for `alr show` (#1333) * Print nested crates under current folder With `alr show --nested`, or after `alr get`/`alr with`. * Test for `alr show --nested` * Do not show when run non-interactive * Self-review --- src/alire/alire-directories.adb | 74 +++++++++++++++++++++---- src/alire/alire-directories.ads | 12 ++++- src/alire/alire-roots.adb | 77 +++++++++++++++++++++++++++ src/alire/alire-roots.ads | 4 ++ src/alr/alr-commands-get.adb | 9 ++++ src/alr/alr-commands-show.adb | 19 +++++-- src/alr/alr-commands-show.ads | 3 +- testsuite/tests/show/nested/test.py | 31 +++++++++++ testsuite/tests/show/nested/test.yaml | 1 + 9 files changed, 213 insertions(+), 17 deletions(-) create mode 100644 testsuite/tests/show/nested/test.py create mode 100644 testsuite/tests/show/nested/test.yaml diff --git a/src/alire/alire-directories.adb b/src/alire/alire-directories.adb index 32f6906e..7b05464f 100644 --- a/src/alire/alire-directories.adb +++ b/src/alire/alire-directories.adb @@ -676,32 +676,84 @@ package body Alire.Directories is Doing : access procedure (Item : Ada.Directories.Directory_Entry_Type; Stop : in out Boolean); - Recurse : Boolean := False) + Recurse : Boolean := False; + Spinner : Boolean := False) is use Ada.Directories; + Visited : AAA.Strings.Set; + -- To avoid infinite recursion in case of softlinks pointed to parent + -- folders + + Progress : Simple_Logging.Ongoing := + Simple_Logging.Activity (Text => "Exploring " & Start, + Level => (if Spinner + then Info + else Debug)); + + procedure Go_Down (Item : Directory_Entry_Type); + + procedure Traverse_Tree_Internal + (Start : Any_Path; + Doing : access procedure + (Item : Ada.Directories.Directory_Entry_Type; + Stop : in out Boolean); + Recurse : Boolean := False) + is + pragma Unreferenced (Doing, Recurse); + begin + Search (Start, + "", + (Directory => True, Ordinary_File => True, others => False), + Go_Down'Access); + end Traverse_Tree_Internal; + procedure Go_Down (Item : Directory_Entry_Type) is - Stop : Boolean := False; + Stop : Boolean := False; + Prune : Boolean := False; begin if Simple_Name (Item) /= "." and then Simple_Name (Item) /= ".." then - Doing (Item, Stop); + begin + Doing (Item, Stop); + exception + when Traverse_Tree_Prune_Dir => + Prune := True; + end; if Stop then return; end if; - if Recurse and then Kind (Item) = Directory then - Traverse_Tree (Start / Simple_Name (Item), Doing, Recurse); + if not Prune and then Recurse and then Kind (Item) = Directory then + declare + Normal_Name : constant String + := + String (GNATCOLL.VFS.Full_Name + (VFS.New_Virtual_File (Full_Name (Item)), + Normalize => True, + Resolve_Links => True).all); + begin + if Visited.Contains (Normal_Name) then + Trace.Debug ("Not revisiting " & Normal_Name); + else + Visited.Insert (Normal_Name); + if Spinner then + Progress.Step ("Exploring .../" & Simple_Name (Item)); + end if; + Traverse_Tree_Internal (Normal_Name, Doing, Recurse); + end if; + end; + elsif Prune and then Kind (Item) = Directory then + Trace.Debug ("Skipping dir: " & Full_Name (Item)); + elsif Prune and then Kind (Item) /= Directory then + Trace.Warning ("Pruning of non-dir entry has no effect: " + & Full_Name (Item)); end if; end if; end Go_Down; begin - Trace.Debug ("Traversing folder: " & Start); - - Search (Start, - "", - (Directory => True, Ordinary_File => True, others => False), - Go_Down'Access); + Trace.Debug ("Traversing folder: " & Adirs.Full_Name (Start)); + Traverse_Tree_Internal (Start, Doing, Recurse); end Traverse_Tree; --------------- diff --git a/src/alire/alire-directories.ads b/src/alire/alire-directories.ads index 70a6d2dd..30ea6d03 100644 --- a/src/alire/alire-directories.ads +++ b/src/alire/alire-directories.ads @@ -90,14 +90,22 @@ package Alire.Directories is -- If the file exists, update last edition time; otherwise create it. If -- File denotes anything else than a regular file, raise. + Traverse_Tree_Prune_Dir : exception; + -- In Traverse_Tree, the Doing procedure can raise this exception to + -- signal that a directory must not be entered, but without stopping + -- the traversal. + procedure Traverse_Tree (Start : Any_Path; Doing : access procedure (Item : Ada.Directories.Directory_Entry_Type; Stop : in out Boolean); - Recurse : Boolean := False); + Recurse : Boolean := False; + Spinner : Boolean := False); -- Traverse all items in a folder, optionally recursively If recursively, -- the directory entry is passed before entering it "." and ".." are - -- ignored. If Stop is set to True, traversal will not continue. + -- ignored. If Stop is set to True, traversal will not continue. See also + -- the comments in Traverse_Tree_Prune_Dir. If Spinner, show a busy spinner + -- with the current dir being explored. function Tree_Size (Path : Any_Path) return Ada.Directories.File_Size; -- Size of files under a given point, in bytes. Will return 0 for an diff --git a/src/alire/alire-roots.adb b/src/alire/alire-roots.adb index 4e575064..2730dd2d 100644 --- a/src/alire/alire-roots.adb +++ b/src/alire/alire-roots.adb @@ -711,6 +711,14 @@ package body Alire.Roots is -- case there is some interaction with some other updated -- dependency, even for crates that didn't change. Run_Post_Fetch (Rel); + + -- If the release was newly deployed, we can inform about its + -- nested crates now. + + if not Was_There and then not CLIC.User_Input.Not_Interactive + then + Print_Nested_Crates (This.Release_Base (Rel.Name)); + end if; end if; end; end Deploy_Release; @@ -1020,6 +1028,75 @@ package body Alire.Roots is Context.Export; end Export_Build_Environment; + ------------------------- + -- Print_Nested_Crates -- + ------------------------- + + procedure Print_Nested_Crates (Path : Any_Path) + is + Starting_Path : constant Absolute_Path := + Ada.Directories.Full_Name (Path); + + CD : Directories.Guard (Directories.Enter (Starting_Path)) + with Unreferenced; + + Found : AAA.Strings.Set; -- Milestone --> Description + + procedure Check_Dir + (Item : Ada.Directories.Directory_Entry_Type; + Stop : in out Boolean) + is + pragma Unreferenced (Stop); + use Ada.Directories; + begin + if Kind (Item) /= Directory then + return; + end if; + + if Simple_Name (Item) = Paths.Working_Folder_Inside_Root + then + -- This is an alire metadata folder, don't go in. It could also be + -- a crate named "alire" but that seems like a bad idea anyway. + raise Directories.Traverse_Tree_Prune_Dir; + end if; + + -- Try to detect a root in this folder + + declare + Opt : constant Optional.Root := + Optional.Detect_Root (Full_Name (Item)); + begin + if Opt.Is_Valid then + Found.Insert + (TTY.URL (Directories.Find_Relative_Path + (Starting_Path, Full_Name (Item))) & "/" + & Opt.Value.Release.Constant_Reference.Milestone.TTY_Image + & ": " & TTY.Emph + (if Opt.Value.Release.Constant_Reference.Description /= "" + then Opt.Value.Release.Constant_Reference.Description + else "(no description)")); + end if; + end; + end Check_Dir; + + begin + Directories.Traverse_Tree (Directories.Current, + Check_Dir'Access, + Recurse => True, + Spinner => True); + + if not Found.Is_Empty then + Put_Info ("Found" & TTY.Bold (Found.Length'Image) + & " nested " + & (if Found.Length in 1 then "crate" else "crates") + & " in " & TTY.URL (Starting_Path) & ":"); + + for Elem of Found loop + Trace.Info (" " & Elem); + end loop; + end if; + end Print_Nested_Crates; + ------------------- -- Project_Paths -- ------------------- diff --git a/src/alire/alire-roots.ads b/src/alire/alire-roots.ads index e09c601d..0abc0e64 100644 --- a/src/alire/alire-roots.ads +++ b/src/alire/alire-roots.ads @@ -273,6 +273,10 @@ package Alire.Roots is procedure Generate_Configuration (This : in out Root); -- Generate or re-generate the crate configuration files + procedure Print_Nested_Crates (Path : Any_Path); + -- Look for nested crates below the given path and print a summary of + -- path/milestone:description for each one found. Won't enter `alire` dirs. + -- Files and folders derived from the root path (this obsoletes Alr.Paths): function Working_Folder (This : Root) return Absolute_Path; diff --git a/src/alr/alr-commands-get.adb b/src/alr/alr-commands-get.adb index 9e7f582e..7cc9db04 100644 --- a/src/alr/alr-commands-get.adb +++ b/src/alr/alr-commands-get.adb @@ -163,6 +163,11 @@ package body Alr.Commands.Get is " use `alr update` to apply dependency changes"); Alire.Config.Edit.Set_Locally (Alire.Config.Keys.Update_Manually, "true"); + + if not CLIC.User_Input.Not_Interactive then + Alire.Roots.Print_Nested_Crates (Cmd.Root.Path); + end if; + return; end if; @@ -217,6 +222,10 @@ package body Alr.Commands.Get is then Info else Warning)); + if not CLIC.User_Input.Not_Interactive then + Alire.Roots.Print_Nested_Crates (Cmd.Root.Path); + end if; + if Diff.Contains_Changes then Trace.Info ("Dependencies were solved as follows:"); Diff.Print (Changed_Only => False); diff --git a/src/alr/alr-commands-show.adb b/src/alr/alr-commands-show.adb index dbba50e9..677f2422 100644 --- a/src/alr/alr-commands-show.adb +++ b/src/alr/alr-commands-show.adb @@ -280,6 +280,15 @@ package body Alr.Commands.Show is begin Cmd.Validate (Args); + -- Early case, --nested doesn't require either root or argument + + if Cmd.Nested then + Alire.Roots.Print_Nested_Crates (Alire.Directories.Current); + return; + end if; + + -- Rest of cases require either being inside a root or a crate name + declare Allowed : constant Alire.Dependencies.Dependency := (if Args.Count = 1 @@ -407,6 +416,10 @@ package body Alr.Commands.Show is Define_Switch (Config, Cmd.Jekyll'Access, "", "--jekyll", "Enable Jekyll output format"); + + Define_Switch (Config, + Cmd.Nested'Access, + "", "--nested", "Show info on nested crates"); end Setup_Switches; -------------- @@ -421,10 +434,10 @@ package body Alr.Commands.Show is end if; if Args.Count = 0 then - if Alire.Root.Current.Outside then + if Alire.Root.Current.Outside and not Cmd.Nested then Reportaise_Wrong_Arguments ("Cannot proceed without a crate name"); - else + elsif not Cmd.Nested then Cmd.Requires_Valid_Session; end if; end if; @@ -441,7 +454,7 @@ package body Alr.Commands.Show is if Cmd.Dependents.all /= "unset" then if Alire.Utils.Count_True ((Cmd.Detect, Cmd.Detail, Cmd.External, Cmd.Graph, Cmd.Solve, Cmd.System, - Cmd.Tree, Cmd.Jekyll)) > 0 + Cmd.Tree, Cmd.Jekyll, Cmd.Nested)) > 0 then Reportaise_Wrong_Arguments ("Switch --dependents is not compatible with other switches"); diff --git a/src/alr/alr-commands-show.ads b/src/alr/alr-commands-show.ads index 4379a53c..bcef0a70 100644 --- a/src/alr/alr-commands-show.ads +++ b/src/alr/alr-commands-show.ads @@ -27,7 +27,7 @@ package Alr.Commands.Show is overriding function Usage_Custom_Parameters (Cmd : Command) return String is ("[[allowed versions]] [--system] [--external[-detect]]" - & " | --graph | --jekyll | --solve | --tree " + & " | --graph | --jekyll | --solve | --tree | --nested" & "| --dependents[=direct|shortest|all]"); private @@ -45,6 +45,7 @@ private System : aliased Boolean := False; Tree : aliased Boolean := False; Jekyll : aliased Boolean := False; + Nested : aliased Boolean := False; end record; end Alr.Commands.Show; diff --git a/testsuite/tests/show/nested/test.py b/testsuite/tests/show/nested/test.py new file mode 100644 index 00000000..90de669f --- /dev/null +++ b/testsuite/tests/show/nested/test.py @@ -0,0 +1,31 @@ +""" +Test working of `alr show --nested` +""" + +from drivers.alr import run_alr, init_local_crate +from drivers.asserts import assert_eq, assert_match + +import os + +# We create a crate below us; this should be detected + +init_local_crate(enter=False) +assert_match(".*Found 1 nested crate in .*:\n" + r" xxx/xxx=0.1.0-dev: \(no description\)\n", + run_alr("show", "--nested", quiet=False).out) + +# After entering the crate, it is no longer nested and shouldn't be detected + +os.chdir("xxx") +assert_match("\s*", + run_alr("show", "--nested", quiet=False).out) + +# If we initialize another crate without entering it, it should again be +# detected + +init_local_crate(name="yyy", enter=False) +assert_match(".*Found 1 nested crate in .*:\n" + r" yyy/yyy=0.1.0-dev: \(no description\)\n", + run_alr("show", "--nested", quiet=False).out) + +print('SUCCESS') diff --git a/testsuite/tests/show/nested/test.yaml b/testsuite/tests/show/nested/test.yaml new file mode 100644 index 00000000..32c747b3 --- /dev/null +++ b/testsuite/tests/show/nested/test.yaml @@ -0,0 +1 @@ +driver: python-script -- 2.39.5