From 0ae936fe53471c7ce3a694c16b29a2f9cc152c22 Mon Sep 17 00:00:00 2001 From: Alejandro R Mosteo Date: Thu, 2 Jul 2020 18:45:46 +0200 Subject: [PATCH] Rework Solutions.Diffs internals to use States (#457) * Rework Solutions.Diffs internals to use States Now that the Solution type stores all relevant information via Dependencies.States, making the diffs directly from the solution is both simpler, more maintainable and more accurate. * Fix unified user pin naming (target --> pin) * Review fixes --- src/alire/alire-dependencies-diffs.adb | 4 +- src/alire/alire-dependencies-states.ads | 30 +- src/alire/alire-solutions-diffs.adb | 480 ++++++++++++-------- src/alire/alire-solutions-diffs.ads | 52 +-- src/alire/alire-solver.adb | 6 +- testsuite/tests/pin/change-type/test.py | 2 +- testsuite/tests/pin/pin-dir/test.py | 2 +- testsuite/tests/with/changes-info/test.py | 155 +++++++ testsuite/tests/with/changes-info/test.yaml | 4 + testsuite/tests/with/pin-dir/test.py | 2 +- 10 files changed, 489 insertions(+), 248 deletions(-) create mode 100644 testsuite/tests/with/changes-info/test.py create mode 100644 testsuite/tests/with/changes-info/test.yaml diff --git a/src/alire/alire-dependencies-diffs.adb b/src/alire/alire-dependencies-diffs.adb index 1a642830..46a5e43e 100644 --- a/src/alire/alire-dependencies-diffs.adb +++ b/src/alire/alire-dependencies-diffs.adb @@ -68,9 +68,9 @@ package body Alire.Dependencies.Diffs is begin if This.Contains_Changes then - Summarize (This.Added, "(added)", + Summarize (This.Added, "(add)", (if TTY.Color_Enabled then TTY.OK ("✓") else "+")); - Summarize (This.Removed, "(removed)", + Summarize (This.Removed, "(remove)", (if TTY.Color_Enabled then TTY.Emph ("✗") else "-")); Table.Print (Info); else diff --git a/src/alire/alire-dependencies-states.ads b/src/alire/alire-dependencies-states.ads index 3f825077..52d0123c 100644 --- a/src/alire/alire-dependencies-states.ads +++ b/src/alire/alire-dependencies-states.ads @@ -89,6 +89,9 @@ package Alire.Dependencies.States is function Is_Pinned (This : State) return Boolean; + function Is_User_Pinned (This : State) return Boolean; + -- From the POV of users, pinning to version or linking to dir is a pin + function Is_Solved (This : State) return Boolean; -- Case-specific info @@ -173,6 +176,20 @@ private end case; end record; + use type Releases.Release; + + overriding function "=" (L, R : Fulfillment_Data) return Boolean + is (L.Fulfillment = R.Fulfillment and then + (case L.Fulfillment is + when Linked => + L.Target.Element.Path = R.Target.Element.Path and then + (L.Opt_Rel.Is_Empty = R.Opt_Rel.Is_Empty and then + (L.Opt_Rel.Is_Empty or else + L.Opt_Rel.Element = R.Opt_Rel.Element)), + when Solved => + L.Release.Element = R.Release.Element, + when others => True)); + type Pinning_Data (Pinned : Boolean := False) is record case Pinned is when True => Version : Semantic_Versioning.Version; @@ -254,10 +271,10 @@ private else "") & Utils.To_Lower_Case (This.Fulfilled.Fulfillment'Img) & (if This.Fulfilled.Fulfillment = Linked - then ",target=" & This.Fulfilled.Target.Get.Path - & (if This.Has_Release - then ",release" - else "") + then ",pin=" & This.Fulfilled.Target.Get.Path + & (if This.Has_Release + then ",release" + else "") else "") & (if This.Pinning.Pinned then ",pin=" & This.Pinning.Version.Image @@ -289,6 +306,9 @@ private function Is_Solved (This : State) return Boolean is (This.Fulfilled.Fulfillment = Solved); + function Is_User_Pinned (This : State) return Boolean + is (This.Is_Pinned or else This.Is_Linked); + ---------- -- Link -- ---------- @@ -452,7 +472,7 @@ private when Hinted => TTY.Warn (This.Fulfilled.Fulfillment'Img), when others => This.Fulfilled.Fulfillment'Img) & (if This.Fulfilled.Fulfillment = Linked - then "," & TTY.Emph ("target") & "=" + then "," & TTY.Emph ("pin") & "=" & TTY.URL (This.Fulfilled.Target.Get.Path) & (if This.Has_Release then "," & TTY.OK ("release") diff --git a/src/alire/alire-solutions-diffs.adb b/src/alire/alire-solutions-diffs.adb index ea128f3c..2c79a844 100644 --- a/src/alire/alire-solutions-diffs.adb +++ b/src/alire/alire-solutions-diffs.adb @@ -10,158 +10,317 @@ package body Alire.Solutions.Diffs is package TTY renames Utils.TTY; - use type Semantic_Versioning.Version; - - ------------------ - -- Best_Version -- - ------------------ + -- Define all changes we can detect, to simplify retrieving their + -- icon/text. These are not exclusive to each other. + type Changes is + (Added, -- A new release + Removed, -- A removed dependency of any kind + Hinted, -- An undetected external dependency + Upgraded, -- An upgraded release + Downgraded, -- A downgraded release + Pinned, -- A release being pinned + Unpinned, -- A release being unpinned + Unchanged, -- An unchanged dependency/release + Missing -- A missing dependency + ); + + ---------- + -- Icon -- + ---------- + + function Icon (Change : Changes) return String + is (if TTY.Color_Enabled then + (case Change is + when Added => TTY.OK ("+"), + when Removed => TTY.Emph ("✗"), + when Hinted => TTY.Warn ("↪"), + when Upgraded => TTY.OK ("⭧"), + when Downgraded => TTY.Warn ("⭨"), + when Pinned => TTY.OK ("⊙"), + when Unpinned => TTY.Emph ("𐩒"), + when Unchanged => TTY.OK ("="), + when Missing => TTY.Error ("⚠")) + else + (case Change is + when Added => "+", + when Removed => "-", + when Hinted => "~", + when Upgraded => "^", + when Downgraded => "v", + when Pinned => "·", + when Unpinned => "o", + when Unchanged => "=", + when Missing => "!")); + + -- This type is used to summarize every detected change + type Crate_Changes is record + Icon, + Best_Version : UString; + Detail : Utils.String_Vector; + end record; + + ---------------- + -- Add_Change -- + ---------------- + + procedure Add_Change (Change : in out Crate_Changes; Icon, Detail : String) + is + use UStrings; + begin + if Icon /= "" and then not Utils.Contains (+Change.Icon, Icon) then + Append (Change.Icon, Icon); + end if; - function Best_Version (Status : Crate_Status) return String is - (case Status.Status is - when Needed => Semantic_Versioning.Image (Status.Version), - when Linked => "file:" & (+Status.Path), - when Hinted => Status.Versions.Image, - when Unneeded => "unneeded", - when Unsolved => Status.Versions.Image); + if Detail /= "" then + Change.Detail.Append (Detail); + end if; + end Add_Change; ------------- -- Between -- ------------- - function Between (Former, Latter : Solution) return Diff is + function Between (Former, Latter : Solution) return Diff + is (Former => Former, Latter => Latter); - use type Containers.Crate_Name_Sets.Set; + ---------------------- + -- Contains_Changes -- + ---------------------- - ----------------- - -- Make_Status -- - ----------------- + function Contains_Changes (This : Diff) return Boolean + is (This.Former /= This.Latter); - function Make_Status (Crate : Crate_Name; - Sol : Solution) return Crate_Status is + ------------------ + -- Find_Changes -- + ------------------ + + function Find_Changes (This : Diff; Crate : Crate_Name) return Crate_Changes + is + Chg : Crate_Changes; + + use UStrings; + use all type Dependencies.States.Fulfillments; + use all type Dependencies.States.Transitivities; + use all type Semantic_Versioning.Version; + + Has_Former : constant Boolean := This.Former.Depends_On (Crate); + Has_Latter : constant Boolean := This.Latter.Depends_On (Crate); + + function Former return Dependencies.States.State + is (This.Former.State (Crate)); + + function Latter return Dependencies.States.State + is (This.Latter.State (Crate)); + + ------------------- + -- Add_Or_Remove -- + ------------------- + + procedure Add_Or_Remove is begin - if Sol.Releases.Contains (Crate) then - return (Status => Needed, - Pinned => Sol.State (Crate).Is_Pinned, - Version => Sol.State (Crate).Release.Version); - elsif Sol.Links.Contains (Crate) then - return (Status => Linked, - Path => +Sol.State (Crate).Link.Path); - elsif Sol.Hints.Contains (Crate) then - return (Status => Hinted, - Versions => Sol.Dependency (Crate).Versions); - - elsif Sol.Depends_On (Crate) then - return (Status => Unsolved, - Versions => Sol.Dependencies (Crate).Versions); + if not Has_Former and then Has_Latter then + Add_Change (Chg, Icon (Added), "new"); + elsif Has_Former and then not Has_Latter then + Add_Change (Chg, Icon (Removed), "removed"); + end if; + end Add_Or_Remove; - else - return (Status => Unneeded); + ------------------- + -- Fulfil_Change -- + ------------------- + + procedure Fulfil_Change is + + ----------------- + -- Gains_State -- + ----------------- + function Gains_State (Fulfilment : Dependencies.States.Fulfillments) + return Boolean + is ((not Has_Former or else Former.Fulfilment not in Fulfilment) + and then Has_Latter and then Latter.Fulfilment in Fulfilment); + + begin + -- New hint + if Gains_State (Hinted) then + Add_Change (Chg, Icon (Hinted), TTY.Warn ("external")); + + -- Changed linked dir target + elsif Has_Latter and then Latter.Is_Linked and then + (not Has_Former or else not Former.Is_Linked or else + Former.Link.Path /= Latter.Link.Path) + then + Add_Change (Chg, Icon (Pinned), + "pin=" & TTY.URL (Latter.Link.Path)); + + -- New unsolvable + elsif Gains_State (Missed) then + Add_Change (Chg, Icon (Missing), TTY.Error ("missing")); + + -- From hint to proper release + elsif Has_Former and then Former.Is_Hinted and then + Gains_State (Solved) + then + -- The crate was formerly in the solution, but not as regular + -- release. Pinning is reported separately, so warn only when + -- it was formerly an external. + Add_Change (Chg, Icon (Added), TTY.OK ("solved")); end if; - end Make_Status; + end Fulfil_Change; - -- Get all involved crates, before and after + -------------------------- + -- transitivity_changed -- + -------------------------- - Crates : constant Containers.Crate_Name_Sets.Set := - Former.Crates or Latter.Crates; - begin - return This : Diff do + procedure Transitivity_Changed is + begin + + -- Inform only when changing from direct to indirect or viceversa. + -- A new direct dependency merits no highlight since it is trivially + -- expected. + + if (not Has_Former or else Former.Transitivity = Direct) and then + Has_Latter and then Latter.Transitivity = Indirect + then + Add_Change (Chg, "", "indirect"); + elsif Has_Former and then Has_Latter and then + Former.Transitivity /= Latter.Transitivity + then + Add_Change (Chg, "", + Utils.To_Lower_Case (Latter.Transitivity'Img)); + end if; + end Transitivity_Changed; + + ------------------------ + -- Pinned_Or_Unpinned -- + ------------------------ + + procedure Pinned_Or_Unpinned is + begin + if (not Has_Former or else not Former.Is_User_Pinned) and then + Has_Latter and then Latter.Is_User_Pinned + then + -- The actual pin change will be shown via version/target + Add_Change (Chg, Icon (Pinned), ""); + elsif Has_Former and then Former.Is_User_Pinned and then + Has_Latter and then not Latter.Is_User_Pinned + then + Add_Change (Chg, Icon (Unpinned), "unpinned"); + end if; + + -- Report pin version when new/changed. Link target already reported + -- in Fulfil_Change. + if Has_Latter and then Latter.Is_Pinned and then + (not Has_Former or else not Former.Is_Pinned or else + Former.Pin_Version /= Latter.Pin_Version) + then + Add_Change (Chg, Icon (Pinned), + "pin=" & TTY.Version (Latter.Pin_Version.Image)); + end if; + end Pinned_Or_Unpinned; + + --------------------- + -- Up_Or_Downgrade -- + --------------------- + + procedure Up_Or_Downgrade is + begin + if Has_Former and then Former.Has_Release and then + Has_Latter and then Latter.Has_Release + then + if Former.Release.Version < Latter.Release.Version then + Add_Change + (Chg, + Icon (Upgraded), + "upgraded from " + & TTY.Version (Former.Release.Version.Image)); + elsif Latter.Release.Version < Former.Release.Version then + Add_Change + (Chg, + Icon (Downgraded), + "downgraded from " + & TTY.Version (Former.Release.Version.Image)); + end if; + + end if; + end Up_Or_Downgrade; + + -------------------------------- + -- Determine_Relevant_Version -- + -------------------------------- + + procedure Determine_Relevant_Version is - -- Solution validities + ------------------ + -- Best_Version -- + ------------------ - This.Former_Complete := Former.Is_Complete; - This.Latter_Complete := Latter.Is_Complete; + function Best_Version (State : Dependencies.States.State) + return String + is (if State.Has_Release then + TTY.Version (State.Release.Version.Image) + elsif State.Is_Linked then -- linked dir without alire metadata + TTY.Warn ("unknown") + elsif State.Is_Hinted then -- undetected external, show dep + TTY.Version (State.Versions.Image) + else -- Not used, but just in case, the crate is in missing state: + TTY.Error (State.Versions.Image)); - -- Store changes for each crate + begin + -- Default to unknown - for Crate of Crates loop - This.Changes.Insert (Crate, - Crate_Changes' - (Former => Make_Status (Crate, Former), - Latter => Make_Status (Crate, Latter))); - end loop; + Chg.Best_Version := +TTY.Error ("unknown"); - end return; - end Between; + -- Find something better - ------------ - -- Change -- - ------------ + if Has_Latter then + Chg.Best_Version := +Best_Version (Latter); + elsif Has_Former then + -- Crate is gone, so it has no current version, show the one + -- disappearing from the solutions. + Chg.Best_Version := +Best_Version (Former); + else + raise Program_Error with "crate is neither in former or latter"; + end if; + + end Determine_Relevant_Version; - function Change (This : Diff; Crate : Crate_Name) return Changes is - Former : Crate_Status renames This.Changes (Crate).Former; - Latter : Crate_Status renames This.Changes (Crate).Latter; begin - -- Changes in pinning take precedence + -- Go through possible changes and add each marker - if Latter.Status = Needed and then Latter.Pinned and then - (Former.Status /= Needed or else not Former.Pinned) - then - return Pinned; - end if; + Add_Or_Remove; + + Pinned_Or_Unpinned; + + Fulfil_Change; + + Transitivity_Changed; - if Former.Status = Needed and then Former.Pinned and then - (Latter.Status /= Needed or else not Latter.Pinned) - then - return Unpinned; + Up_Or_Downgrade; + + Determine_Relevant_Version; + + -- Final fill-in for no changes + + if Length (Chg.Icon) = 0 then + Add_Change (Chg, Icon (Unchanged), ""); end if; - -- Other changes that don't involve pinning - - return - (case Latter.Status is - when Needed => - (if Former.Status = Needed then - (if Former.Version < Latter.Version then Upgraded - elsif Former.Version = Latter.Version then Unchanged - else Downgraded) - else Added), - when Linked => Pinned, - when Hinted => External, - when Unneeded => Removed, - when Unsolved => Unsolved); - end Change; + if Chg.Detail.Is_Empty then + Add_Change (Chg, "", "unchanged"); + end if; - ---------------------- - -- Contains_Changes -- - ---------------------- + return Chg; - function Contains_Changes (This : Diff) return Boolean is - (This.Former_Complete /= This.Latter_Complete or else - (for some Change of This.Changes => Change.Former /= Change.Latter)); + end Find_Changes; ------------------------ -- Latter_Is_Complete -- ------------------------ function Latter_Is_Complete (This : Diff) return Boolean - is (This.Latter_Complete); - - ------------------------ - -- Pin_Change_Summary -- - ------------------------ - - function Pin_Change_Summary (Former, Latter : Crate_Status) return String - is - begin - -- Show what's going on with versions - - if Former.Status = Needed and then Latter.Status = Needed then - if Former.Version < Latter.Version then - return ", upgraded from " & TTY.Version (Former.Version.Image); - elsif Former.Version = Latter.Version then - return ", version unchanged"; - else - return ", downgraded from " & TTY.Version (Former.Version.Image); - end if; - elsif Former.Status = Needed and then Latter.Status /= Needed then - return " from " & TTY.Version (Former.Version.Image); - else - -- Pinned, nothing else to say - return ""; - end if; - end Pin_Change_Summary; + is (This.Latter.Is_Complete); ----------- -- Print -- @@ -172,111 +331,62 @@ package body Alire.Solutions.Diffs is Prefix : String := " "; Level : Trace.Levels := Trace.Info) is - use Change_Maps; - - package Semver renames Semantic_Versioning; - Table : Utils.Tables.Table; + Changed : Boolean := False; begin -- Start with an empty line to separate from previous output Trace.Log ("", Level); - if not This.Latter_Complete then + if not This.Latter.Is_Complete then Trace.Log (Prefix & "New solution is " & TTY.Warn ("incomplete."), Level); - elsif This.Latter_Complete and then not This.Former_Complete then + elsif This.Latter.Is_Complete and then not This.Former.Is_Complete then Trace.Log (Prefix & "New solution is " & TTY.OK ("complete."), Level); end if; - -- Early exit if no changes - - if Changed_Only and then not This.Contains_Changes then - Trace.Log (Prefix & "No changes between former an new solution.", - Level); - return; - end if; - -- Detailed changes otherwise - for I in This.Changes.Iterate loop + for Crate of This.Former.Crates.Union (This.Latter.Crates) loop declare - Former : Crate_Status renames This.Changes (I).Former; - Latter : Crate_Status renames This.Changes (I).Latter; + Changes : constant Crate_Changes := Find_Changes (This, Crate); begin - if not Changed_Only or else Former /= Latter then + + if not Changed_Only or else + Changes.Detail.Flatten /= "unchanged" + then + Changed := Changed or True; -- Show icon of change - if TTY.Color_Enabled then - Table.Append - (Prefix - & (case This.Change (Key (I)) is - when Added => TTY.OK ("✓"), - when Removed => TTY.Emph ("✗"), - when External => TTY.Warn ("↪"), - when Upgraded => TTY.OK ("⭧"), - when Downgraded => TTY.Warn ("⭨"), - when Pinned => TTY.OK ("⊙"), - when Unpinned => TTY.Emph ("𐩒"), - when Unchanged => TTY.OK ("="), - when Unsolved => TTY.Error ("⚠"))); - else - Table.Append - (Prefix - & (case This.Change (Key (I)) is - when Added => "+", - when Removed => "-", - when External => "~", - when Upgraded => "^", - when Downgraded => "v", - when Pinned => ".", - when Unpinned => "o", - when Unchanged => "=", - when Unsolved => "!")); - end if; + Table.Append (Prefix & (+Changes.Icon)); -- Always show crate name - Table.Append (TTY.Name (+Key (I))); + Table.Append (TTY.Name (Crate)); -- Show most precise version available - if Latter.Status in Unsolved | Hinted | Linked | Needed then - Table.Append (TTY.Version (Best_Version (Latter))); - else - Table.Append (TTY.Version (Best_Version (Former))); - end if; + Table.Append (+Changes.Best_Version); -- Finally show an explanation of the change depending on -- status changes. - Table.Append - ("(" - & (case This.Change (Key (I)) is - when Added => "new", - when Removed => "removed", - when External => "external", - when Upgraded => "upgraded from " - & TTY.Version (Semver.Image (Former.Version)), - when Downgraded => "downgraded from " - & TTY.Version (Semver.Image (Former.Version)), - when Pinned => "pinned" - & Pin_Change_Summary (Former, Latter), - when Unpinned => "unpinned" - & Pin_Change_Summary (Former, Latter), - when Unchanged => "unchanged", - when Unsolved => "missing") - & ")"); + Table.Append ("(" & Changes.Detail.Flatten (",") & ")"); Table.New_Row; end if; end; end loop; - Table.Print (Level); + if Changed then + Table.Print (Level); + else + Trace.Log (Prefix & "No changes between former an new solution.", + Level); + end if; end Print; end Alire.Solutions.Diffs; diff --git a/src/alire/alire-solutions-diffs.ads b/src/alire/alire-solutions-diffs.ads index b1b67636..73e7f947 100644 --- a/src/alire/alire-solutions-diffs.ads +++ b/src/alire/alire-solutions-diffs.ads @@ -1,30 +1,13 @@ with Semantic_Versioning.Extended; -private with Ada.Containers.Indefinite_Ordered_Maps; - package Alire.Solutions.Diffs is - type Changes is - (Added, -- A new release - Removed, -- A removed dependency of any kind - External, -- A new external dependency - Upgraded, -- An upgraded release - Downgraded, -- A downgraded release - Pinned, -- A release being pinned - Unpinned, -- A release being unpinned - Unchanged, -- An unchanged dependency/release - Unsolved -- A missing dependency - ); - type Diff is tagged private; -- Encapsulates the differences between two solutions function Between (Former, Latter : Solution) return Diff; -- Create a Diff from two solutions - function Change (This : Diff; Crate : Crate_Name) return Changes; - -- Summary of what happened with a crate - function Contains_Changes (This : Diff) return Boolean; -- Says if there are, in fact, changes between both solutions @@ -40,41 +23,8 @@ package Alire.Solutions.Diffs is private - type Install_Status is (Unsolved, Unneeded, Hinted, Linked, Needed); - -- Unsolved will apply to all crates when a solution is invalid. TODO: when - -- reasons for solving failure are tracked, improve the diff output. - - type Crate_Status (Status : Install_Status := Unneeded) is record - case Status is - when Needed => - Pinned : Boolean; - Version : Semantic_Versioning.Version; - when Linked => - Path : UString; - when Hinted | Unsolved => - Versions : Semantic_Versioning.Extended.Version_Set; - when Unneeded => - null; - end case; - end record; - - function Best_Version (Status : Crate_Status) return String; - -- Used to provide the most precise version available depending on the - -- crate status. - - type Crate_Changes is record - Former, Latter : Crate_Status := (Status => Unneeded); - end record; - - package Change_Maps is new Ada.Containers.Indefinite_Ordered_Maps - (Crate_Name, Crate_Changes); - type Diff is tagged record - Former_Complete, - Latter_Complete : Boolean := False; - -- Empty solutions but with different validity still count as changes. - - Changes : Change_Maps.Map; + Former, Latter : Solution; end record; end Alire.Solutions.Diffs; diff --git a/src/alire/alire-solver.adb b/src/alire/alire-solver.adb index 10dc9a79..ec20f4c1 100644 --- a/src/alire/alire-solver.adb +++ b/src/alire/alire-solver.adb @@ -603,8 +603,10 @@ package body Alire.Solver is -- Mark pins as direct dependencies - for Dep of Conditional.Dependencies'(Current.Pins) loop - Best_Solution.Set (Dep.Value.Crate, Direct); + for Dep of Best_Solution.Required loop + if Dep.Is_User_Pinned then + Best_Solution.Set (Dep.Crate, Direct); + end if; end loop; -- Mark direct dependencies diff --git a/testsuite/tests/pin/change-type/test.py b/testsuite/tests/pin/change-type/test.py index d950ea4f..132d2386 100644 --- a/testsuite/tests/pin/change-type/test.py +++ b/testsuite/tests/pin/change-type/test.py @@ -36,7 +36,7 @@ p = run_alr('show', '--solve') s = re.escape(path_separator()) # platform-dependent assert_match('.*Dependencies \(external\):.*' 'libhello\* \(direct,linked' - ',target=.*' + s + 'my_index' + s + + ',pin=.*' + s + 'my_index' + s + 'crates' + s + 'libhello_1.0.0\).*', p.out, flags=re.S) diff --git a/testsuite/tests/pin/pin-dir/test.py b/testsuite/tests/pin/pin-dir/test.py index 2ec13acb..4a86c8bf 100644 --- a/testsuite/tests/pin/pin-dir/test.py +++ b/testsuite/tests/pin/pin-dir/test.py @@ -32,7 +32,7 @@ p = run_alr('with', '--solve') s = re.escape(path_separator()) # platform-dependent assert_match('.*Dependencies \(external\):.*' 'libhello\* \(direct,linked' - ',target=.*' + s + 'my_index' + s + + ',pin=.*' + s + 'my_index' + s + 'crates' + s + 'libhello_1.0.0\).*', p.out, flags=re.S) diff --git a/testsuite/tests/with/changes-info/test.py b/testsuite/tests/with/changes-info/test.py new file mode 100644 index 00000000..7d21391f --- /dev/null +++ b/testsuite/tests/with/changes-info/test.py @@ -0,0 +1,155 @@ +""" +Check summary of changes shown to the user when modifying dependencies +""" + +import os +import re + +from drivers.alr import run_alr +from drivers.asserts import assert_match +from drivers.helpers import path_separator, with_project + +# Initialize a workspace for the test +run_alr('init', '--bin', 'xxx') +os.chdir('xxx') + +############################################################################### +# Add a regular solvable dependency +p = run_alr('with', 'libhello', quiet=False) +assert_match(re.escape("""Requested changes: + + + libhello * (add) + +Changes to dependency solution: + + + libhello 2.0.0 (new)""") + ".*", + p.out, flags=re.S) + +############################################################################### +# Check adding a missing crate +p = run_alr('with', 'unobtanium', quiet=False) +assert_match(".*" + + re.escape("""Requested changes: + + + unobtanium * (add) + +Changes to dependency solution: + + New solution is incomplete. + +! unobtanium * (new,missing)""") + ".*", + p.out, flags=re.S) + +############################################################################### +# Check adding a pinned dir +p = run_alr('with', 'local_crate', '--use=/', quiet=False) +assert_match(".*" + + re.escape("""Requested changes: + + + local_crate * (add) + +Changes to dependency solution: + + +· local_crate unknown (new,pin=""") + ".*", # skip platform-dependent path + p.out, flags=re.S) + +############################################################################### +# Pinning a crate to a version +p = run_alr('pin', 'libhello', quiet=False) +assert_match(".*" + + re.escape("""Changes to dependency solution: + + · libhello 2.0.0 (pin=2.0.0)""") + ".*", + p.out, flags=re.S) + +############################################################################### +# Unpinning +p = run_alr('pin', '--unpin', 'libhello', quiet=False) +assert_match(".*" + + re.escape("""Changes to dependency solution: + + o libhello 2.0.0 (unpinned)""") + ".*", + p.out, flags=re.S) + +############################################################################### +# Removal +p = run_alr('with', '--del', 'libhello', quiet=False) +assert_match(".*" + + re.escape("""Requested changes: + + - libhello * (remove) + +Changes to dependency solution: + + - libhello 2.0.0 (removed)""") + ".*", + p.out, flags=re.S) + +############################################################################### +# Indirect dependency +p = run_alr('with', 'hello', quiet=False) +assert_match(".*" + + re.escape("""Requested changes: + + + hello * (add) + +Changes to dependency solution: + + + hello 1.0.1 (new)""") + "\s*\n\s*" + + re.escape("+ libhello 1.1.0 (new,indirect)") + ".*", + p.out, flags=re.S) + +############################################################################### +# Going from indirect to direct. Since the dependency is already in the +# solution, there is no version change (=). +p = run_alr('with', 'libhello', quiet=False) +assert_match(".*" + + re.escape("""Requested changes: + + + libhello * (add) + +Changes to dependency solution: + + = libhello 1.1.0 (direct)""") + ".*", + p.out, flags=re.S) + +############################################################################### +# Going from direct to indirect. Likewise, removing the dependency leaves it in +# the solution because is still needed indirectly via 'hello' +p = run_alr('with', '--del', 'libhello', quiet=False) +assert_match(".*" + + re.escape("""Requested changes: + + - libhello * (remove) + +Changes to dependency solution: + + = libhello 1.1.0 (indirect)""") + ".*", + p.out, flags=re.S) + +############################################################################### +# Display of downgrades. Forcing libhello=1, it results in a downgrade. +p = run_alr('with', 'libhello=1', quiet=False) +assert_match(".*" + + re.escape("""Requested changes: + + + libhello =1 (add) + +Changes to dependency solution: + + v libhello 1.0.0 (direct,downgraded from 1.1.0)""") + ".*", + p.out, flags=re.S) + +############################################################################### +# Display of upgrades. By removing libhello=1, it can be upgraded. +p = run_alr('with', '--del', 'libhello', quiet=False) +assert_match(".*" + + re.escape("""Requested changes: + + - libhello =1 (remove) + +Changes to dependency solution: + + ^ libhello 1.1.0 (indirect,upgraded from 1.0.0)""") + ".*", + p.out, flags=re.S) + + +print('SUCCESS') diff --git a/testsuite/tests/with/changes-info/test.yaml b/testsuite/tests/with/changes-info/test.yaml new file mode 100644 index 00000000..e0a82ba8 --- /dev/null +++ b/testsuite/tests/with/changes-info/test.yaml @@ -0,0 +1,4 @@ +driver: python-script +indexes: + solver_index: + in_fixtures: true diff --git a/testsuite/tests/with/pin-dir/test.py b/testsuite/tests/with/pin-dir/test.py index ba183a14..c1f8d216 100644 --- a/testsuite/tests/with/pin-dir/test.py +++ b/testsuite/tests/with/pin-dir/test.py @@ -31,7 +31,7 @@ p = run_alr('with', '--solve') s = re.escape(path_separator()) # platform-dependent assert_match('.*Dependencies \(external\):.*' 'libhello\* \(direct,linked' - ',target=.*' + s + 'my_index' + s + + ',pin=.*' + s + 'my_index' + s + 'crates' + s + 'libhello_1.0.0\).*', p.out, flags=re.S) -- 2.39.5