From 6c8fcb9bc86be70c0c4bdc958d968c3ca5794022 Mon Sep 17 00:00:00 2001 From: Alejandro R Mosteo Date: Sat, 26 Jun 2021 15:27:29 +0200 Subject: [PATCH] Reinstante `alr with --pin` (#758) * Implement temporary root copies * Preparations for manifest modification via Roots This way, alr with/alr pin become mere proxies for the Alire.Roots functions, which is as it should have been from the start. * User_Pins: programmatic creation and TOML oneliner * Roots manifest editor procedures * Moved root edition to Alire.Roots.Editable * Reinstated `alr with [crate] --use` * Narrowing-down of dependencies without pin * Tweaks for existing `with` tests * Re-enabled tests depending on `alr with --use` * Tweaks found during self-review * Attempt to fix error in older GNATs --- deps/optional | 2 +- deps/semantic_versioning | 2 +- src/alire/alire-conditional_trees.ads | 4 +- src/alire/alire-lockfiles.adb | 3 +- src/alire/alire-lockfiles.ads | 3 +- src/alire/alire-manifest.adb | 88 ++-- src/alire/alire-manifest.ads | 16 +- src/alire/alire-optional.ads | 4 + src/alire/alire-pinning.adb | 54 --- src/alire/alire-pinning.ads | 33 -- src/alire/alire-roots-editable.adb | 431 +++++++++++++++++ src/alire/alire-roots-editable.ads | 126 +++++ src/alire/alire-roots-optional.adb | 4 +- src/alire/alire-roots.adb | 154 ++++-- src/alire/alire-roots.ads | 82 +++- src/alire/alire-solutions.adb | 10 +- src/alire/alire-solutions.ads | 8 +- src/alire/alire-solver.adb | 3 +- src/alire/alire-solver.ads | 4 +- src/alire/alire-tty.ads | 3 + src/alire/alire-user_pins.adb | 82 +++- src/alire/alire-user_pins.ads | 31 +- src/alire/alire-utils-text_files.adb | 14 + src/alire/alire-utils-text_files.ads | 6 + src/alire/alire.ads | 3 +- src/alr/alr-commands-init.adb | 2 +- src/alr/alr-commands-pin.adb | 26 +- src/alr/alr-commands-update.adb | 4 +- src/alr/alr-commands-withing.adb | 447 ++++-------------- src/alr/alr-commands.adb | 7 +- testsuite/disabled/with/changes-info/test.py | 7 +- testsuite/disabled/with/pin-dir/test.py | 6 +- .../disabled/with/pin-transitive/test.py | 8 +- .../tests/with/dynamic-dependencies/test.py | 3 - testsuite/tests/with/no-double-add/test.py | 4 +- .../with/pin-dir-crate-autodetect/test.py | 0 .../with/pin-dir-crate-autodetect/test.yaml | 0 .../with/pin-dir-crate/test.py | 0 .../with/pin-dir-crate/test.yaml | 0 .../with/pin-dir-mismatch/test.py | 0 .../with/pin-dir-mismatch/test.yaml | 0 .../with/tree-switch/test.py | 5 +- .../with/tree-switch/test.yaml | 0 .../with/versions-switch/test.py | 3 +- .../with/versions-switch/test.yaml | 0 45 files changed, 1072 insertions(+), 620 deletions(-) delete mode 100644 src/alire/alire-pinning.adb delete mode 100644 src/alire/alire-pinning.ads create mode 100644 src/alire/alire-roots-editable.adb create mode 100644 src/alire/alire-roots-editable.ads create mode 100644 src/alire/alire-tty.ads rename testsuite/{disabled => tests}/with/pin-dir-crate-autodetect/test.py (100%) rename testsuite/{disabled => tests}/with/pin-dir-crate-autodetect/test.yaml (100%) rename testsuite/{disabled => tests}/with/pin-dir-crate/test.py (100%) rename testsuite/{disabled => tests}/with/pin-dir-crate/test.yaml (100%) rename testsuite/{disabled => tests}/with/pin-dir-mismatch/test.py (100%) rename testsuite/{disabled => tests}/with/pin-dir-mismatch/test.yaml (100%) rename testsuite/{disabled => tests}/with/tree-switch/test.py (86%) rename testsuite/{disabled => tests}/with/tree-switch/test.yaml (100%) rename testsuite/{disabled => tests}/with/versions-switch/test.py (95%) rename testsuite/{disabled => tests}/with/versions-switch/test.yaml (100%) diff --git a/deps/optional b/deps/optional index eb929e67..0c7d20c0 160000 --- a/deps/optional +++ b/deps/optional @@ -1 +1 @@ -Subproject commit eb929e67ccd357881997d4eed5e4477144923d7c +Subproject commit 0c7d20c0c8b48ccb6b25fb648d48382e598c25c3 diff --git a/deps/semantic_versioning b/deps/semantic_versioning index 85689acb..fe4e72e4 160000 --- a/deps/semantic_versioning +++ b/deps/semantic_versioning @@ -1 +1 @@ -Subproject commit 85689acb6dfde74d00473b41563b75adf76f4881 +Subproject commit fe4e72e40786589a66d53662639f894fcdb3419c diff --git a/src/alire/alire-conditional_trees.ads b/src/alire/alire-conditional_trees.ads index 977d3028..a042ea0f 100644 --- a/src/alire/alire-conditional_trees.ads +++ b/src/alire/alire-conditional_trees.ads @@ -249,9 +249,7 @@ package Alire.Conditional_Trees with Preelaborate is package Iterators is new Ada.Iterator_Interfaces (Cursor, Has_Element); function Iterate (Container : Tree) return Iterators.Forward_Iterator'Class - with Pre => Container.Is_Empty or else - Container.Root in Leaf_Node or else - Container.Root in Vector_Node; + with Pre => Container.Is_Iterable; -- Returns our own iterator. function Indexed_Element (Container : Tree; Pos : Cursor) return Tree; diff --git a/src/alire/alire-lockfiles.adb b/src/alire/alire-lockfiles.adb index 7c2dd3a1..9e8eb80d 100644 --- a/src/alire/alire-lockfiles.adb +++ b/src/alire/alire-lockfiles.adb @@ -26,8 +26,7 @@ package body Alire.Lockfiles is -- File_Name -- --------------- - function File_Name (Name : Crate_Name; - Root_Dir : Any_Path) return Any_Path + function File_Name (Root_Dir : Any_Path) return Any_Path is (Root_Dir / "alire.lock"); --------------- diff --git a/src/alire/alire-lockfiles.ads b/src/alire/alire-lockfiles.ads index 3e43e119..f3800032 100644 --- a/src/alire/alire-lockfiles.ads +++ b/src/alire/alire-lockfiles.ads @@ -21,8 +21,7 @@ package Alire.Lockfiles is end record; -- Information that goes in the lockfile - function File_Name (Name : Crate_Name; - Root_Dir : Any_Path) return Any_Path; + function File_Name (Root_Dir : Any_Path) return Any_Path; -- Return the location /path/to/crate/dir/alire.lock, filename included, -- given the root directory where the crate is deployed. diff --git a/src/alire/alire-manifest.adb b/src/alire/alire-manifest.adb index 3bca84ef..25ae460b 100644 --- a/src/alire/alire-manifest.adb +++ b/src/alire/alire-manifest.adb @@ -1,5 +1,3 @@ -with Ada.Text_IO; use Ada.Text_IO; - with Alire.Directories; with Alire.Errors; with Alire.Paths; @@ -16,45 +14,37 @@ package body Alire.Manifest is ------------ procedure Append (Name : Any_Path; - Deps : Dependencies.Containers.List) is - Replacer : constant Directories.Replacer := - Directories.New_Replacement - (Name, - Backup => True, - Backup_Dir => Paths.Working_Folder_Inside_Root); - File : File_Type; + Dep : Dependencies.Dependency) + is begin - if Deps.Is_Empty then - return; - end if; - - Open (File, Append_File, Replacer.Editable_Name); - - for Dep of Deps loop - New_Line (File); - Put_Line (File, "[[" & TOML_Keys.Depends_On & "]]" & Warning); - Put_Line (File, Dep.Manifest_Image & Warning); - end loop; - - Close (File); - - -- Attempt loading of the new file as a double check - if not Is_Valid (Replacer.Editable_Name, Local) then - raise Program_Error - with Errors.Set ("Addition of dependencies to manifest failed"); - end if; + Utils.Text_Files.Append_Lines + (File => Name, + Lines => + Utils.Empty_Vector + .Append ("[[" & TOML_Keys.Depends_On & "]]" & Warning) + .Append (Dep.Manifest_Image & Warning), + Backup => False); + -- No need to backup, as this is done already on a copy of the manifest - Replacer.Replace; -- All went well, keep the changes - exception - when E : others => - Trace.Debug ("Exception attempting to append dependencies:"); - Alire.Log_Exception (E); + end Append; - if Is_Open (File) then - Close (File); - end if; + ------------ + -- Append -- + ------------ - raise; -- Let it be processed upwards, if necessary + procedure Append (File : Any_Path; + Crate : Crate_Name; + Pin : User_Pins.Pin) + is + begin + Utils.Text_Files.Append_Lines + (File => File, + Lines => + Utils.Empty_Vector + .Append ("[[" & TOML_Keys.Pins & "]]" & Warning) + .Append (Pin.To_Manifest_Line (Crate) & " " & Warning), + Backup => False); + -- No need to backup as this is done on a copy of the manifest already end Append; -------------- @@ -85,21 +75,21 @@ package body Alire.Manifest is ------------ procedure Remove (Name : Any_Path; - Deps : Dependencies.Containers.List) + Dep : Crate_Name) is ------------ -- Remove -- ------------ - procedure Remove (Dep : Dependencies.Dependency; + procedure Remove (Dep : Crate_Name; Lines : in out Utils.String_Vector) -- Remove given Dep from Lines, or warn if impossible is Enter_Marker : constant String := "[[" & TOML_Keys.Depends_On & "]]"; -- We must see a line like this before being able to remove a dep. - Target : constant String := (+Dep.Crate) & "="""; + Target : constant String := Dep.As_String & "="""; -- A line starting with Target is a candidate for deletion Armed : Boolean := False; @@ -246,9 +236,6 @@ package body Alire.Manifest is Backup => True, Backup_Dir => Paths.Working_Folder_Inside_Root); begin - if Deps.Is_Empty then - return; - end if; declare File : constant Utils.Text_Files.File := @@ -256,9 +243,7 @@ package body Alire.Manifest is Backup => False); -- Replacer takes care of backup begin - for Dep of Deps loop - Remove (Dep, File.Lines.all); - end loop; + Remove (Dep, File.Lines.all); end; -- Attempt loading of the new file as a double check. This should never @@ -271,4 +256,15 @@ package body Alire.Manifest is Replacer.Replace; -- All went well, keep the changes end Remove; + ---------------- + -- Remove_Pin -- + ---------------- + + procedure Remove_Pin (File : Any_Path; + Pin : Crate_Name) + is + begin + raise Unimplemented; + end Remove_Pin; + end Alire.Manifest; diff --git a/src/alire/alire-manifest.ads b/src/alire/alire-manifest.ads index f127e8cd..c7c1f769 100644 --- a/src/alire/alire-manifest.ads +++ b/src/alire/alire-manifest.ads @@ -1,4 +1,5 @@ -with Alire.Dependencies.Containers; +with Alire.Dependencies; +with Alire.User_Pins; package Alire.Manifest is @@ -9,14 +10,23 @@ package Alire.Manifest is -- Subprograms for manipulation of the manifest file procedure Append (Name : Any_Path; - Deps : Dependencies.Containers.List); + Dep : Dependencies.Dependency); procedure Remove (Name : Any_Path; - Deps : Dependencies.Containers.List); + Dep : Crate_Name); -- Do a best effort to remove dependencies; if we cannot locate a -- dependency with enough guarantees of not botching the manifest, -- no change will be applied and Checked_Error will be raised. + procedure Append (File : Any_Path; + Crate : Crate_Name; + Pin : User_Pins.Pin); + + procedure Remove_Pin (File : Any_Path; + Pin : Crate_Name); + -- As removal of dependencies, but for pins. If the pin is not found, or + -- it cannot be safely removed, it will raise. + function Is_Valid (Name : Any_Path; Source : Sources) return Boolean; -- Check that the given Name is a loadable manifest diff --git a/src/alire/alire-optional.ads b/src/alire/alire-optional.ads index 9120113e..8b29a671 100644 --- a/src/alire/alire-optional.ads +++ b/src/alire/alire-optional.ads @@ -4,6 +4,10 @@ package Alire.Optional with Preelaborate is -- Optional basic types + package Crate_Names is + new Standard.Optional.Values (Crate_Name, As_String); + subtype Crate_Name is Crate_Names.Optional; + function String_Image (Str : Standard.String) return Standard.String is (Str); package Strings is new Standard.Optional.Values (String, String_Image); diff --git a/src/alire/alire-pinning.adb b/src/alire/alire-pinning.adb deleted file mode 100644 index 382d242e..00000000 --- a/src/alire/alire-pinning.adb +++ /dev/null @@ -1,54 +0,0 @@ -with Alire.Solver; - -package body Alire.Pinning is - - use type Conditional.Dependencies; - - --------- - -- Pin -- - --------- - - function Pin (Crate : Crate_Name; - Version : Semantic_Versioning.Version; - Dependencies : Conditional.Dependencies; - Environment : Properties.Vector; - Solution : Solutions.Solution) - return Solutions.Solution - is - -- We solve forcing the new version, while preemptively removing any - -- previous pin for the same crate, since two pins to different versions - -- would be unsolvable. A link is also preemptively removed to prevent - -- simultaneous pinning and linking. - begin - return - Solver.Resolve - (Conditional.New_Dependency (Crate, Version) and Dependencies, - Environment, - Solution.Unpinning (Crate).Missing (Crate)) - .Pinning (Crate, Version); - end Pin; - - ----------- - -- Unpin -- - ----------- - - function Unpin (Crate : Crate_Name; - Dependencies : Conditional.Dependencies; - Environment : Properties.Vector; - Solution : Solutions.Solution) - return Solutions.Solution - is - begin - -- The unpin case is simpler since we need only to remove any previous - -- pin for the crate, and let the solver operate normally. Likewise for - -- a linked dependency. - - return Solver.Resolve - (Dependencies, - Environment, - Solution - .Missing (Crate) -- Clears any previous link - .Unpinning (Crate)); -- Clears any previous pin - end Unpin; - -end Alire.Pinning; diff --git a/src/alire/alire-pinning.ads b/src/alire/alire-pinning.ads deleted file mode 100644 index 481c8b3b..00000000 --- a/src/alire/alire-pinning.ads +++ /dev/null @@ -1,33 +0,0 @@ -with Alire.Conditional; -with Alire.Properties; -with Alire.Solutions; - -with Semantic_Versioning; - -package Alire.Pinning is - - -- Index MUST be loaded previously to using these functions - - function Pin (Crate : Crate_Name; - Version : Semantic_Versioning.Version; - Dependencies : Conditional.Dependencies; - Environment : Properties.Vector; - Solution : Solutions.Solution) - return Solutions.Solution - with Pre => Solution.Depends_On (Crate); - -- Compute a new solution after applying the pin to the given crate, that - -- must exist in the solution. Root dependencies are given, and a previous - -- solution with possibly more pins. The resulting solution may be invalid. - - function Unpin (Crate : Crate_Name; - Dependencies : Conditional.Dependencies; - Environment : Properties.Vector; - Solution : Solutions.Solution) - return Solutions.Solution - with Pre => Solution.Depends_On (Crate) and then - (Solution.State (Crate).Is_Linked or else - Solution.State (Crate).Is_Pinned); - -- Compute a new solution removing the pin of the given crate, that must - -- be pinned and in the solution. The resulting solution might be invalid. - -end Alire.Pinning; diff --git a/src/alire/alire-roots-editable.adb b/src/alire/alire-roots-editable.adb new file mode 100644 index 00000000..1dd3cd5e --- /dev/null +++ b/src/alire/alire-roots-editable.adb @@ -0,0 +1,431 @@ +with Alire.Conditional; +with Alire.Dependencies.Diffs; +with Alire.Directories; +with Alire.Manifest; +with Alire.Roots.Optional; +with Alire.User_Pins; +with Alire.Utils.User_Input; +with Alire.VCSs.Git; + +with Semantic_Versioning.Extended; + +package body Alire.Roots.Editable is + + package Semver renames Semantic_Versioning; + + -------------- + -- New_Root -- + -------------- + + function New_Root (Original : in out Roots.Root) return Root + is + begin + return Result : Root do + Result.Orig := Original; + Result.Edit := Roots.Root (Original.Temporary_Copy); + end return; + end New_Root; + + ------------------------ + -- Confirm_And_Commit -- + ------------------------ + + procedure Confirm_And_Commit (This : in out Root) is + Original : Roots.Root renames This.Orig; + Edited : Roots.Root renames This.Edit; + begin + declare + Dep_Diff : constant Dependencies.Diffs.Diff := + Dependencies.Diffs.Between + (Former => Release (Original) + .Dependencies (Original.Environment), + Latter => Release (Edited) + .Dependencies (Edited.Environment)); + begin + + -- First show requested changes + + if Dep_Diff.Contains_Changes then + Trace.Info ("Requested changes:"); + Trace.Info (""); + Dep_Diff.Print; + end if; + + -- Compute the new solution + + Edited.Set (Solution => Edited.Compute_Update); + + -- Then show the effects on the solution + + if Alire.Utils.User_Input.Confirm_Solution_Changes + (Original.Solution.Changes (Edited.Solution), + Changed_Only => not Alire.Detailed) + then + Edited.Commit; + else + Trace.Info ("No changes applied."); + end if; + end; + end Confirm_And_Commit; + + -------------------- + -- Add_Dependency -- + -------------------- + + procedure Add_Dependency (This : in out Root; + Dep : Dependencies.Dependency) + is + + -------------------- + -- Find_Updatable -- + -------------------- + + function Find_Updatable return Dependencies.Dependency is + begin + + -- Solve with the new dependency and take the updatable set for the + -- version in the solution. + + Trace.Debug ("Attempting to narrow down dependency for new crate " + & Dep.TTY_Image); + + declare + use type Conditional.For_Dependencies.Tree; + Sol : constant Solutions.Solution := + Solver.Resolve + (Deps => Release (This.Edit) + .Dependencies (This.Edit.Environment) + and Dep, + Props => This.Edit.Environment, + Current => This.Edit.Solution); + begin + if Sol.State (Dep.Crate).Has_Release then + return + Dependencies.New_Dependency + (Crate => Dep.Crate, + Versions => Semver.Updatable + (Sol.State (Dep.Crate).Release.Version)); + else + return Dep; + end if; + + exception + when Solver.No_Solution_Error => + Put_Warning ("No solution found when adding dependency: " + & Dep.TTY_Image); + return Dep; + end; + end Find_Updatable; + + begin + + -- Do not add if already a direct dependency + + if (for some Existing_Dep of Release (This.Edit).Flat_Dependencies => + Existing_Dep.Crate = Dep.Crate) + then + raise Checked_Error with Errors.Set + (TTY.Name (Dep.Crate) & " is already a direct dependency."); + end if; + + -- If we are given an Any dependency, attempt a solving to narrow down + -- to a "safely updatable" subset. + + declare + Dep : constant Dependencies.Dependency := + (if Add_Dependency.Dep.Versions.Is_Any + then Find_Updatable + else Add_Dependency.Dep); + begin + Alire.Manifest.Append (Crate_File (This.Edit), Dep); + This.Reload_Manifest; + + This.Edit.Set (This.Solution.Depending_On (Dep)); + end; + end Add_Dependency; + + ----------------------- + -- Remove_Dependency -- + ----------------------- + + procedure Remove_Dependency (This : in out Root; + Crate : Crate_Name; + Unpin : Boolean := True) + is + pragma Unreferenced (Unpin); + begin + + -- TODO: remove pin if existing too (next PR) + + -- If dependency is not among dependencies at all, nothing to do + + if not (for some Dep of Release (This.Edit).Flat_Dependencies => + Dep.Crate = Crate) + then + Raise_Checked_Error + ("Requested crate is not among direct dependencies."); + end if; + + -- If dependency is not among the top-level direct dependencies, this is + -- a dynamic dependency + + if not Release (This.Edit).Dependencies.Is_Iterable + or else + not (for some Dep of + Release (This.Edit).Dependencies => + Dep.Is_Value and then Dep.Value.Crate = Crate) + then + Raise_Checked_Error + ("Crate slated for removal is not among direct static dependencies:" + & " " & TTY.Name (Crate) + & "; please remove manually from manifest."); + end if; + + Alire.Manifest.Remove (This.Edit.Crate_File, Crate); + This.Reload_Manifest; + + end Remove_Dependency; + + --------------------- + -- Add_Version_Pin -- + --------------------- + + procedure Add_Version_Pin (This : in out Root; + Crate : Crate_Name; + Version : String) + is + V : constant Semver.Version := Semver.Parse (Version); + begin + if not This.Solution.Depends_On (Crate) then + This.Add_Dependency + (Dependencies.New_Dependency + (Crate, + Semver.Updatable (V))); + end if; + + -- Remove any previous pin for this crate + + This.Remove_Pin (Crate); + + -- And add the new pin + + Alire.Manifest.Append (Crate_File (This.Edit), + Crate, + User_Pins.New_Version (V)); + This.Reload_Manifest; + + This.Edit.Set (This.Solution.Pinning (Crate, V)); + end Add_Version_Pin; + + -------------------------- + -- Add_Pin_Preparations -- + -------------------------- + + function Add_Pin_Preparations (This : in out Root; + Crate : Alire.Optional.Crate_Name; + Path : Any_Path) + return Crate_Name + is + Pin_Root : constant Optional.Root := Optional.Detect_Root (Path); + begin + if Crate.Is_Empty and then not Pin_Root.Is_Valid then + Raise_Checked_Error + ("No crate name given and link target is not an Alire crate:" + & ASCII.LF & " Please provide an explicit crate name."); + end if; + + -- No need to check that Pin_Root.Name and Crate agree, as this will be + -- done by the pin loader. + + declare + -- At this point we can be sure of the crate name, so we shadow the + -- original argument. + Crate : constant Crate_Name := + (if Add_Pin_Preparations.Crate.Has_Element + then Add_Pin_Preparations.Crate.Element.Ptr.all + else Pin_Root.Value.Name); + begin + + if not This.Solution.Depends_On (Crate) then + This.Add_Dependency + (Dependencies.New_Dependency + (Crate, + (if Pin_Root.Is_Valid + then Pin_Root.Updatable_Dependency.Versions + else Semver.Extended.Any))); + end if; + + -- Remove any previous pin for this crate + + This.Remove_Pin (Crate); + + return Crate; + end; + end Add_Pin_Preparations; + + ------------------ + -- Add_Path_Pin -- + ------------------ + + procedure Add_Path_Pin (This : in out Root; + Crate : Alire.Optional.Crate_Name; + Path : Any_Path) + is + Abs_Path : constant Absolute_Path := Ada.Directories.Full_Name (Path); + Added : constant Crate_Name := + Add_Pin_Preparations (This, Crate, Abs_Path); + New_Pin : constant User_Pins.Pin := User_Pins.New_Path (Abs_Path); + begin + -- And add the new pin + + Alire.Manifest.Append + (Crate_File (This.Edit), + Added, + New_Pin); + This.Reload_Manifest; + + This.Edit.Set (This.Solution.Linking (Added, New_Pin)); + + -- Since link pins can bring in more dependencies, we must also Update. + -- Changes will be shown afterwards on the call to Confirm_And_Commit. + This.Edit.Update (Allow_All_Crates, + Silent => True, + Interact => False); + end Add_Path_Pin; + + -------------------- + -- Add_Remote_Pin -- + -------------------- + + procedure Add_Remote_Pin (This : in out Root; + Crate : Alire.Optional.Crate_Name; + Origin : URL; + Commit : String := ""; + Branch : String := "") + is + Temp_Pin : Directories.Temp_File; + -- We'll need to fetch the remote to a temporary location to verify + -- crate matches. If all goes well, we will keep the download so there + -- is no need to redownload on next run. + begin + if not VCSs.Git.Handler.Clone + (From => Origin & (if Commit /= "" + then "#" & Commit + else ""), + Into => Temp_Pin.Filename, + Branch => Branch, -- May be empty for default branch + Depth => 1).Success + then + Raise_Checked_Error + ("Checkout of repository at " & TTY.URL (Origin) + & " failed, re-run with -vv -d for details"); + end if; + + -- We can proceed as if it where a local pin now + + declare + Crate : constant Crate_Name := + Add_Pin_Preparations (This, + Add_Remote_Pin.Crate, + Temp_Pin.Filename); + New_Pin : User_Pins.Pin := + User_Pins.New_Remote (URL => Origin, + Commit => Commit, + Branch => Branch); + + Destination : constant Absolute_Path := + New_Pin.Deploy_Path (Crate, This.Edit.Pins_Dir); + + package Adirs renames Ada.Directories; + begin + + -- Put in place the checkout, as it is valid if we reached this point + + if not Adirs.Exists (This.Edit.Pins_Dir) then + Adirs.Create_Path (This.Edit.Pins_Dir); + end if; + + if Adirs.Exists (Destination) then + -- Remove a previous pin deployment, which may be obsolete + Adirs.Delete_Tree (Destination); + end if; + + Adirs.Rename (Old_Name => Temp_Pin.Filename, + New_Name => Destination); + + -- Finally add the new pin to the manifest + + Alire.Manifest.Append (Crate_File (This.Edit), + Crate, + User_Pins.New_Remote (URL => Origin, + Commit => Commit, + Branch => Branch)); + This.Reload_Manifest; + + -- And update lockfile. We need to "deploy" the pin (it's already + -- deployed) so the pin becomes aware of its own path. + + New_Pin.Deploy (Crate, This.Edit.Pins_Dir, Online => False); + This.Edit.Set (This.Solution.Linking (Crate, New_Pin)); + + -- Since link pins can bring in more dependencies, we must + -- also Update. Changes will be shown afterwards on the call + -- to Confirm_And_Commit. + This.Edit.Update (Allow_All_Crates, + Silent => True, + Interact => False); + end; + end Add_Remote_Pin; + + ---------------- + -- Remove_Pin -- + ---------------- + + procedure Remove_Pin (This : in out Root; Crate : Crate_Name) + is + begin + if This.Solution.Depends_On (Crate) + and then This.Solution.State (Crate).Is_User_Pinned + then + Alire.Manifest.Remove_Pin (Lock_File (This.Edit), + Crate); + This.Edit.Set (This.Solution.User_Unpinning (Crate)); + end if; + end Remove_Pin; + + --------------------- + -- Reload_Manifest -- + --------------------- + + procedure Reload_Manifest (This : in out Root) is + begin + This.Edit.Reload_Manifest; + end Reload_Manifest; + + -------------- + -- Finalize -- + -------------- + + overriding procedure Finalize (This : in out Root) is + + procedure Finalize (File : String) is + begin + if File /= "" then + declare + Temp : Directories.Temp_File := Directories.With_Name (File) + with Unreferenced; + begin + Trace.Debug ("Discarding temporary root file: " & File); + end; + end if; + end Finalize; + + begin + Finalize (+This.Edit.Manifest); + Finalize (+This.Edit.Lockfile); + exception + when E : others => + Log_Exception (E, Warning); + end Finalize; + +end Alire.Roots.Editable; diff --git a/src/alire/alire-roots-editable.ads b/src/alire/alire-roots-editable.ads new file mode 100644 index 00000000..e8b849c4 --- /dev/null +++ b/src/alire/alire-roots-editable.ads @@ -0,0 +1,126 @@ +private with Ada.Finalization; + +with Alire.Dependencies; +with Alire.Errors; +with Alire.Optional; +with Alire.TTY; + +package Alire.Roots.Editable is + + -- This type mimics manual edition of the manifest. All operations in here + -- modify the manifest as if it were done by hand. + + type Root (<>) is tagged limited private; + + function New_Root (Original : in out Roots.Root) return Root; + -- This creates a temporary root with separate manifest and lockfile, + -- but shared cache with the Original. Changes will be forgotten unless + -- Confirm_And_Commit is called. + + procedure Confirm_And_Commit (This : in out Root); + -- Present differences in the solutions of Original and Edited and ask + -- the user to accept, in which case Edited.Commit is called. Edited + -- is expected to be a temporary copy of Original. Performs an + -- Edited.Reload_Manifest, so any changes done to the Edited manifest + -- about dependency/pin adition/removal are applied. + + -- A few proxies so useful predicates can be kept + + function Name (This : Root) return Crate_Name; + + function Solution (This : in out Root) return Solutions.Solution; + + -- Edition procedures + + procedure Reload_Manifest (This : in out Root); + -- If changes have been done to the manifest, either via the dependency/pin + -- modification procedures, or somehow outside alire after This was + -- created, we need to reload the manifest. The solution remains + -- untouched (use Update to recompute a fresh solution). + + procedure Add_Dependency (This : in out Root; + Dep : Dependencies.Dependency); + -- Add a dependency, or raise Checked_Error is Dep is already among direct + -- dependencies. + + procedure Remove_Dependency (This : in out Root; + Crate : Crate_Name; + Unpin : Boolean := True); + -- Remove any dependency (and pin) on crate; will raise Checked_Error if + -- Crate is not a dependency already. + + function Can_Be_Pinned (This : in out Root; + Crate : Crate_Name) + return Boolean + is (not This.Solution.Depends_On (Crate) + or else not This.Solution.State (Crate).Is_User_Pinned + or else Force + or else raise Checked_Error with Errors.Set + (TTY.Name (Crate) & " is already pinned to " + & This.Solution.State (Crate).Image)); + -- Says if a pin can be added: not already a pin, or Force. As an + -- exception, the body is here as this function is intended to serve as + -- a precondition, an hence serve as documentation. + + procedure Add_Version_Pin (This : in out Root; + Crate : Crate_Name; + Version : String) + with Pre => This.Can_Be_Pinned (Crate); + -- Add a version pin; if the root doesn't depend on it previously, the + -- dependency will be added too. + + procedure Add_Path_Pin (This : in out Root; + Crate : Optional.Crate_Name; + Path : Any_Path) + with Pre => + Crate.Is_Empty + or else This.Can_Be_Pinned (Crate.Element.Ptr.all); + -- Add a pin to a folder; if Crate.Is_Empty then Path must point to an + -- Alire workspace from which it can be deduced. If Crate.Has_Element, the + -- crates should match. If the root does not depend already on the crate, + -- a dependency will be added. + + procedure Add_Remote_Pin (This : in out Root; + Crate : Optional.Crate_Name; + Origin : URL; + Commit : String := ""; + Branch : String := "") + with Pre => + (not (Commit /= "" and then Branch /= "") + or else raise Checked_Error with + Errors.Set ("Simultaneous Branch and Commit pins are incompatible")) + and then + (Crate.Is_Empty + or else This.Can_Be_Pinned (Crate.Element)); + -- Add a pin to a remote repo, with optional Commit xor Branch. if + -- Crate.Is_Empty then Path must point to an Alire workspace for which it + -- can be deduced. If Crate.Has_Element, the crates should match. If the + -- root does not depend already on the crate, a dependency will be added. + + procedure Remove_Pin (This : in out Root; Crate : Crate_Name); + -- Remove the pin for Crate if existing; otherwise do nothing + +private + + type Root is new Ada.Finalization.Limited_Controlled with record + Orig : Roots.Root; + Edit : Roots.Root; + end record; + + overriding procedure Finalize (This : in out Root); + + ---------- + -- Name -- + ---------- + + function Name (This : Root) return Crate_Name + is (This.Edit.Name); + + -------------- + -- Solution -- + -------------- + + function Solution (This : in out Root) return Solutions.Solution + is (This.Edit.Solution); + +end Alire.Roots.Editable; diff --git a/src/alire/alire-roots-optional.adb b/src/alire/alire-roots-optional.adb index 56bd9e78..77231bb4 100644 --- a/src/alire/alire-roots-optional.adb +++ b/src/alire/alire-roots-optional.adb @@ -52,8 +52,8 @@ package body Alire.Roots.Optional is Outcome_Success (Roots.New_Root (R => Releases.From_Manifest (Crate_File, - Manifest.Local, - Strict => True), + Manifest.Local, + Strict => True), Path => Ada.Directories.Full_Name (Path), Env => Alire.Root.Platform_Properties)) do diff --git a/src/alire/alire-roots.adb b/src/alire/alire-roots.adb index 861ecb14..6a12f55b 100644 --- a/src/alire/alire-roots.adb +++ b/src/alire/alire-roots.adb @@ -1,8 +1,7 @@ -with Ada.Directories; - with Alire.Conditional; with Alire.Crate_Configuration; with Alire.Dependencies.Containers; +with Alire.Dependencies; with Alire.Directories; with Alire.Environment; with Alire.Manifest; @@ -22,6 +21,8 @@ package body Alire.Roots is package Semver renames Semantic_Versioning; package TTY renames Utils.TTY; + use type UString; + ------------------- -- Build_Context -- ------------------- @@ -641,10 +642,13 @@ package body Alire.Roots is function New_Root (R : Releases.Release; Path : Absolute_Path; Env : Properties.Vector) return Root is - (Environment => Env, + (Ada.Finalization.Controlled with + Environment => Env, Path => +Path, Release => Containers.To_Release_H (R), - Cached_Solution => <>); + Cached_Solution => <>, + Lockfile => <>, + Manifest => <>); ---------- -- Name -- @@ -703,17 +707,23 @@ package body Alire.Roots is -- Lock_File -- --------------- - function Lock_File (This : Root) return Absolute_Path is - (Lockfiles.File_Name - (This.Release.Constant_Reference.Name, - +This.Path)); + function Lock_File (This : Root) return Absolute_Path + is (if This.Lockfile /= "" + then +This.Lockfile + else Lockfiles.File_Name (+This.Path)); ---------------- -- Crate_File -- ---------------- - function Crate_File (This : Root) return Absolute_Path is - (Path (This) / Crate_File_Name); + function Crate_File (This : Root) return Absolute_Path + is (if This.Manifest /= "" + then +This.Manifest + else Path (This) / Crate_File_Name); + + --------------- + -- Cache_Dir -- + --------------- function Cache_Dir (This : Root) return Absolute_Path is (This.Working_Folder / "cache"); @@ -782,9 +792,10 @@ package body Alire.Roots is -- Sync_From_Manifest -- ------------------------ - procedure Sync_From_Manifest (This : in out Root; - Silent : Boolean; - Force : Boolean := False) + procedure Sync_From_Manifest (This : in out Root; + Silent : Boolean; + Interact : Boolean; + Force : Boolean := False) is Old_Solution : constant Solutions.Solution := This.Solution; begin @@ -802,8 +813,9 @@ package body Alire.Roots is -- a non-exhaustive sync of pins, that will anyway detect evident -- changes (new/removed pins, changed explicit commits). - This.Sync_Dependencies (Old => Old_Solution, - Silent => Silent); + This.Sync_Dependencies (Old => Old_Solution, + Silent => Silent, + Interact => Interact); -- Don't ask for confirmation as this is an automatic update in -- reaction to a manually edited manifest, and we need the lockfile -- to match the manifest. As any change in dependencies will be @@ -862,8 +874,10 @@ package body Alire.Roots is -- Update -- ------------ - procedure Update (This : in out Root; - Allowed : Containers.Crate_Name_Sets.Set) + procedure Update (This : in out Root; + Allowed : Containers.Crate_Name_Sets.Set; + Silent : Boolean; + Interact : Boolean) is Old : constant Solutions.Solution := This.Solution; begin @@ -875,9 +889,10 @@ package body Alire.Roots is -- And look for updates in dependencies This.Sync_Dependencies - (Allowed => Allowed, - Old => Old, - Silent => Alire.Utils.User_Input.Not_Interactive); + (Allowed => Allowed, + Old => Old, + Silent => Silent, + Interact => Interact and not Alire.Utils.User_Input.Not_Interactive); end Update; -------------------- @@ -923,11 +938,12 @@ package body Alire.Roots is ----------------------- procedure Sync_Dependencies - (This : in out Root; - Silent : Boolean; - Old : Solutions.Solution := Solutions.Empty_Invalid_Solution; - Options : Solver.Query_Options := Solver.Default_Options; - Allowed : Containers.Crate_Name_Sets.Set := + (This : in out Root; + Silent : Boolean; -- Do not output anything + Interact : Boolean; -- Request confirmation from the user + Old : Solutions.Solution := Solutions.Empty_Invalid_Solution; + Options : Solver.Query_Options := Solver.Default_Options; + Allowed : Containers.Crate_Name_Sets.Set := Alire.Containers.Crate_Name_Sets.Empty_Set) is begin @@ -979,16 +995,24 @@ package body Alire.Roots is -- In case manual changes in manifest do not modify the -- solution. - Trace.Info ("Nothing to update."); + if not Silent then + Trace.Info ("Nothing to update."); + end if; else -- Show changes and optionally ask user to apply them - if Silent then - Trace.Info - ("Dependencies automatically updated as follows:"); - Diff.Print; + if not Interact then + declare + Level : constant Trace.Levels := + (if Silent then Debug else Info); + begin + Trace.Log + ("Dependencies automatically updated as follows:", + Level); + Diff.Print (Level => Level); + end; elsif not Utils.User_Input.Confirm_Solution_Changes (Diff) then Trace.Detail ("Update abandoned."); return; @@ -1030,4 +1054,74 @@ package body Alire.Roots is .To_File (This.Crate_File, Manifest.Local); end Write_Manifest; + -------------------- + -- Temporary_Copy -- + -------------------- + + function Temporary_Copy (This : in out Root) return Root'Class is + Copy : Root := This; + + Temp_Manifest : Directories.Temp_File; + Temp_Lockfile : Directories.Temp_File; + begin + Temp_Manifest.Keep; + Temp_Lockfile.Keep; + + Copy.Manifest := +Temp_Manifest.Filename; + Ada.Directories.Copy_File (Source_Name => This.Crate_File, + Target_Name => +Copy.Manifest); + + Copy.Lockfile := +Temp_Lockfile.Filename; + Copy.Set (Solution => This.Solution); + + return Copy; + end Temporary_Copy; + + ------------ + -- Commit -- + ------------ + + procedure Commit (This : in out Root) is + + Regular_Root : constant Root := Load_Root (Path (This)); + -- We use a regular root to extract the paths of manifest and lockfile. + -- A bit overkill but entirely more readable than messing with paths. + + procedure Commit (Source, Target : Absolute_File) is + begin + if Source /= "" then + Directories.Backup_If_Existing (Target, + Base_Dir => This.Working_Folder); + Ada.Directories.Copy_File (Source_Name => Source, + Target_Name => Target); + Ada.Directories.Delete_File (Source); + end if; + end Commit; + + begin + Commit (+This.Manifest, Crate_File (Regular_Root)); + This.Manifest := +""; + + Commit (+This.Lockfile, Lock_File (Regular_Root)); + This.Lockfile := +""; + + This.Sync_From_Manifest (Silent => True, + Interact => False); + end Commit; + + --------------------- + -- Reload_Manifest -- + --------------------- + + procedure Reload_Manifest (This : in out Root) is + begin + -- Load our manifest + + This.Release.Replace_Element + (Releases.From_Manifest + (This.Crate_File, + Manifest.Local, + Strict => True)); + end Reload_Manifest; + end Alire.Roots; diff --git a/src/alire/alire-roots.ads b/src/alire/alire-roots.ads index 5bc20f03..820dfe3a 100644 --- a/src/alire/alire-roots.ads +++ b/src/alire/alire-roots.ads @@ -1,4 +1,6 @@ private with AAA.Caches.Files; +with Ada.Directories; +private with Ada.Finalization; with Alire.Containers; limited with Alire.Environment; @@ -125,9 +127,10 @@ package Alire.Roots is -- conceivably we could use checksums to make it more robust against -- automated changes within the same second. - procedure Sync_From_Manifest (This : in out Root; - Silent : Boolean; - Force : Boolean := False); + procedure Sync_From_Manifest (This : in out Root; + Silent : Boolean; + Interact : Boolean; + Force : Boolean := False); -- If the lockfile timestamp is outdated w.r.t the manifest, or Force, do -- as follows: 1) Pre-deploy any remote pins in the manifest so they are -- usable when solving, and apply any local/version pins. 2) Ensure that @@ -135,7 +138,8 @@ package Alire.Roots is -- the manifest is newer than the lockfile, resolve again, as dependencies -- may have been edited by hand. 3) Ensure that releases in the lockfile -- are actually on disk (may be missing if cache was deleted, or the crate - -- was just cloned). When Silent, run as in non-interactive mode. + -- was just cloned). When Silent, downgrade log level of some output. When + -- not Interact, run as if --non-interactive were in effect. procedure Sync_Manifest_And_Lockfile_Timestamps (This : Root) with Post => not This.Is_Lockfile_Outdated; @@ -144,19 +148,13 @@ package Alire.Roots is -- edited but the solution hasn't changed (and so the lockfile hasn't been -- regenerated). This way we know the lockfile is valid for the manifest. - function Compute_Update - (This : in out Root; - Allowed : Containers.Crate_Name_Sets.Set := - Containers.Crate_Name_Sets.Empty_Set; - Options : Solver.Query_Options := Solver.Default_Options) - return Solutions.Solution; - -- Compute a new solution for the workspace. If Allowed is not empty, - -- crates not appearing in Allowed are held back at their current version. - -- This function loads configured indexes from disk. No changes are - -- applied to This root. + Allow_All_Crates : Containers.Crate_Name_Sets.Set renames + Containers.Crate_Name_Sets.Empty_Set; - procedure Update (This : in out Root; - Allowed : Containers.Crate_Name_Sets.Set); + procedure Update (This : in out Root; + Allowed : Containers.Crate_Name_Sets.Set; + Silent : Boolean; + Interact : Boolean); -- Full update, explicitly requested. Will fetch/prune pins, update any -- updatable crates. Equivalent to `alr update`. Allowed is an optionally -- empty set of crates to which the update will be limited. Everything is @@ -166,11 +164,12 @@ package Alire.Roots is -- Download all dependencies not already on disk from This.Solution procedure Sync_Dependencies - (This : in out Root; - Silent : Boolean; - Old : Solutions.Solution := Solutions.Empty_Invalid_Solution; - Options : Solver.Query_Options := Solver.Default_Options; - Allowed : Containers.Crate_Name_Sets.Set := + (This : in out Root; + Silent : Boolean; -- Do not output anything + Interact : Boolean; -- Request confirmation from the user + Old : Solutions.Solution := Solutions.Empty_Invalid_Solution; + Options : Solver.Query_Options := Solver.Default_Options; + Allowed : Containers.Crate_Name_Sets.Set := Alire.Containers.Crate_Name_Sets.Empty_Set); -- Resolve and update all or given crates in a root, and regenerate -- configuration. When Silent, run as in non-interactive mode as this is an @@ -193,6 +192,13 @@ package Alire.Roots is procedure Write_Manifest (This : Root); -- Generates the crate.toml manifest at the appropriate location for Root + procedure Reload_Manifest (This : in out Root) + with Pre => This.Path = Ada.Directories.Current_Directory; + -- If changes have been done to the manifest, either via the dependency/pin + -- modification procedures, or somehow outside alire after This was + -- created, we need to reload the manifest. The solution remains + -- untouched (use Update to recompute a fresh solution). + -- Files and folders derived from the root path (this obsoletes Alr.Paths): function Working_Folder (This : Root) return Absolute_Path; @@ -227,11 +233,43 @@ private Load => Load_Solution, Write => Write_Solution); - type Root is tagged record + type Root is new Ada.Finalization.Controlled with record Environment : Properties.Vector; Path : UString; Release : Containers.Release_H; Cached_Solution : Cached_Solutions.Cache; + + -- These values, if different from "", mean this is a temporary root + Manifest : Unbounded_Absolute_Path; + Lockfile : Unbounded_Absolute_Path; end record; + -- Support for editable roots begins here. These are not expected to be + -- directly useful to clients, so better kept them under wraps. + + function Compute_Update + (This : in out Root; + Allowed : Containers.Crate_Name_Sets.Set := + Containers.Crate_Name_Sets.Empty_Set; + Options : Solver.Query_Options := Solver.Default_Options) + return Solutions.Solution; + -- Compute a new solution for the workspace. If Allowed is not empty, + -- crates not appearing in Allowed are held back at their current version. + -- This function loads configured indexes from disk. No changes are applied + -- to This root. NOTE: pins have to be added to This.Solution beforehand, + -- or they will not be applied. + + function Temporary_Copy (This : in out Root) return Root'Class; + -- Obtain a temporary copy of This root, in the sense that it uses temp + -- names for the manifest and lockfile. The cache is shared, so any + -- pins/dependencies added to the temporary copy are ready if the copy is + -- commited (see Commit call). The intended use is to be able to modify + -- the temporary manifest, and finally compare the solutions between This + -- and its copy. This way, no logic remains in `alr with`/`alr pin`, for + -- example, as they simply edit the manifest as if the user did it by hand. + + procedure Commit (This : in out Root); + -- Renames the manifest and lockfile to their regular places, making this + -- root a regular one to all effects. + end Alire.Roots; diff --git a/src/alire/alire-solutions.adb b/src/alire/alire-solutions.adb index 3551b773..c7913a87 100644 --- a/src/alire/alire-solutions.adb +++ b/src/alire/alire-solutions.adb @@ -896,11 +896,11 @@ package body Alire.Solutions is end return; end To_TOML; - ------------------------------- - -- Restrict_New_Dependencies -- - ------------------------------- + ----------------------------- + -- Narrow_New_Dependencies -- + ----------------------------- - function Restrict_New_Dependencies (Old_Deps, + function Narrow_New_Dependencies (Old_Deps, New_Deps : Conditional.Dependencies; New_Sol : Solution) return Conditional.Dependencies @@ -952,6 +952,6 @@ package body Alire.Solutions is end if; end loop; end return; - end Restrict_New_Dependencies; + end Narrow_New_Dependencies; end Alire.Solutions; diff --git a/src/alire/alire-solutions.ads b/src/alire/alire-solutions.ads index 2ce7b3ff..85b8fafb 100644 --- a/src/alire/alire-solutions.ads +++ b/src/alire/alire-solutions.ads @@ -349,10 +349,10 @@ package Alire.Solutions is -- Utilities -- --------------- - function Restrict_New_Dependencies (Old_Deps, - New_Deps : Conditional.Dependencies; - New_Sol : Solution) - return Conditional.Dependencies; + function Narrow_New_Dependencies (Old_Deps, + New_Deps : Conditional.Dependencies; + New_Sol : Solution) + return Conditional.Dependencies; -- Take new dependencies in a tree, see how they've been solved, and -- replace "any" dependencies with the proper tilde or caret, depending on -- what was found in the solution. E.g., if the user provided lib=*, and it diff --git a/src/alire/alire-solver.adb b/src/alire/alire-solver.adb index c4f4a14b..7833a7e0 100644 --- a/src/alire/alire-solver.adb +++ b/src/alire/alire-solver.adb @@ -4,6 +4,7 @@ with Ada.Containers.Indefinite_Ordered_Sets; with Alire.Conditional; with Alire.Containers; with Alire.Dependencies.States; +with Alire.Errors; with Alire.Milestones; with Alire.Utils.TTY; @@ -799,7 +800,7 @@ package body Alire.Solver is Detecting => Options.Detecting, Hinting => Options.Hinting))); else - Raise_Checked_Error + raise No_Solution_Error with Errors.Set ("Solver failed to find any solution to fulfill dependencies."); end if; else diff --git a/src/alire/alire-solver.ads b/src/alire/alire-solver.ads index c8db29ed..1ed15d88 100644 --- a/src/alire/alire-solver.ads +++ b/src/alire/alire-solver.ads @@ -9,6 +9,8 @@ with Semantic_Versioning.Extended; package Alire.Solver is + No_Solution_Error : exception; + -------------- -- Policies -- -------------- @@ -134,7 +136,7 @@ package Alire.Solver is return Solution; -- Exhaustively look for a solution to the given dependencies, under the -- given platform properties and lookup options. Pins can be supplied to - -- override Deps. + -- override Deps. May raise No_Solution_Error. function Is_Resolvable (Deps : Types.Abstract_Dependencies; Props : Properties.Vector; diff --git a/src/alire/alire-tty.ads b/src/alire/alire-tty.ads new file mode 100644 index 00000000..48efeb6c --- /dev/null +++ b/src/alire/alire-tty.ads @@ -0,0 +1,3 @@ +with Alire.Utils.TTY; + +package Alire.TTY renames Alire.Utils.TTY; diff --git a/src/alire/alire-user_pins.adb b/src/alire/alire-user_pins.adb index fbffa40d..9ea8d094 100644 --- a/src/alire/alire-user_pins.adb +++ b/src/alire/alire-user_pins.adb @@ -14,6 +14,8 @@ package body Alire.User_Pins is package TTY renames Alire.Utils.TTY; + use type UString; + package Keys is Branch : constant String := "branch"; Commit : constant String := "commit"; @@ -23,6 +25,36 @@ package body Alire.User_Pins is Version : constant String := "version"; end Keys; + ----------------- + -- New_Version -- + ----------------- + + function New_Version (Version : Semantic_Versioning.Version) return Pin + is (Kind => To_Version, + Version => Version); + + -------------- + -- New_Path -- + -------------- + + function New_Path (Path : Any_Path) return Pin + is (Kind => To_Path, + Path => +Path); + + ---------------- + -- New_Remote -- + ---------------- + + function New_Remote (URL : Alire.URL; + Commit : String := ""; + Branch : String := "") + return Pin + is (Kind => To_Git, + URL => +URL, + Commit => +Commit, + Branch => +Branch, + Local_Path => <>); + ----------- -- Image -- ----------- @@ -41,6 +73,27 @@ package body Alire.User_Pins is else "") & ("url=" & This.TTY_URL_With_Reference)); + ---------------------- + -- To_Manifest_Line -- + ---------------------- + + function To_Manifest_Line (This : Pin; + Crate : Crate_Name) + return String + is (Crate.As_String + & " = { " + & (case This.Kind is + when To_Version => "version='" & This.Version.Image & "'", + when To_Path => "path='" & Path (This) & "'", + when To_Git => + "url='" & (+This.URL) & "'" + & (if This.Branch /= "" + then ", branch='" & (+This.Branch) & "'" + elsif This.Commit /= "" + then ", commit='" & (+This.Commit) & "'" + else "")) + & " }"); + --------------- -- Is_Broken -- --------------- @@ -50,6 +103,25 @@ package body Alire.User_Pins is or else Ada.Directories.Kind (Path (This)) not in Ada.Directories.Directory); + ----------------- + -- Deploy_Path -- + ----------------- + + function Deploy_Path (This : Pin; + Crate : Crate_Name; + Under : Any_Path) + return Absolute_Path + is + use Directories.Operators; + begin + return Ada.Directories.Full_Name + (Under + / (Crate.As_String + & (if This.Is_Remote and then This.Commit /= "" + then "_" & Origins.Short_Commit (+This.Commit) + else ""))); + end Deploy_Path; + ------------ -- Deploy -- ------------ @@ -60,16 +132,8 @@ package body Alire.User_Pins is Online : Boolean) is use Ada.Strings.Unbounded; - use Directories.Operators; - - Folder : constant String := - (+Crate) - & (if This.Is_Remote and then This.Commit /= "" - then "_" & Origins.Short_Commit (+This.Commit) - else ""); - Destination : constant String := - Ada.Directories.Full_Name (Under / Folder); + Destination : constant Absolute_Path := This.Deploy_Path (Crate, Under); -------------- -- Checkout -- diff --git a/src/alire/alire-user_pins.ads b/src/alire/alire-user_pins.ads index 0043a3a0..63c0da6a 100644 --- a/src/alire/alire-user_pins.ads +++ b/src/alire/alire-user_pins.ads @@ -32,12 +32,18 @@ package Alire.User_Pins is function Is_Remote (This : Pin) return Boolean; -- A pin to a remote source such as git, source archives, etc - -- Version attributes + -- Version pins + + function New_Version (Version : Semantic_Versioning.Version) return Pin + with Post => New_Version'Result.Kind = To_Version; function Version (This : Pin) return Semantic_Versioning.Version with Pre => This.Kind = To_Version; - -- Local path attributes + -- Local path pins + + function New_Path (Path : Any_Path) return Pin + with Post => New_Path'Result.Kind = To_Path; function Is_Broken (This : Pin) return Boolean with Pre => This.Kind in Kinds_With_Path; @@ -53,7 +59,13 @@ package Alire.User_Pins is -- Convenience to show to users. May still return an absolute path for -- paths in another drive on Windows. May include TTY sequences. - -- Remote attributes + -- Remote pins + + function New_Remote (URL : Alire.URL; + Commit : String := ""; + Branch : String := "") + return Pin + with Post => New_Remote'Result.Kind = To_Git; function URL (This : Pin) return Alire.URL with Pre => This.Is_Remote; @@ -70,6 +82,14 @@ package Alire.User_Pins is with Pre => This.Is_Remote; -- returns https://blah[#commit|#branch], when existing + function Deploy_Path (This : Pin; + Crate : Crate_Name; + Under : Any_Path) + return Absolute_Path + with Pre => This.Kind in Kinds_With_Path; + -- Says where this pin would be deployed, without doing nothing else. Under + -- is the umbrella folder for all pins of a root. + procedure Deploy (This : in out Pin; Crate : Crate_Name; Under : Any_Path; @@ -101,6 +121,11 @@ package Alire.User_Pins is with Pre => This.Kind in Kinds_With_Path; -- Used by the lockfile + function To_Manifest_Line (This : Pin; + Crate : Crate_Name) + return String; + -- Returns the single line that describes this pin in a manifest + private type Pin (Kind : Kinds) is tagged record diff --git a/src/alire/alire-utils-text_files.adb b/src/alire/alire-utils-text_files.adb index cc035edf..9f1769d9 100644 --- a/src/alire/alire-utils-text_files.adb +++ b/src/alire/alire-utils-text_files.adb @@ -4,6 +4,20 @@ with Alire.Directories; package body Alire.Utils.Text_Files is + ------------------ + -- Append_Lines -- + ------------------ + + procedure Append_Lines (File : Any_Path; + Lines : String_Vector; + Backup : Boolean := True; + Backup_Dir : Any_Path := "") + is + F : Text_Files.File := Load (File, Backup, Backup_Dir); + begin + F.Lines.Append (Lines); + end Append_Lines; + -------------- -- Finalize -- -------------- diff --git a/src/alire/alire-utils-text_files.ads b/src/alire/alire-utils-text_files.ads index 6233e0f1..764ec663 100644 --- a/src/alire/alire-utils-text_files.ads +++ b/src/alire/alire-utils-text_files.ads @@ -16,6 +16,12 @@ package Alire.Utils.Text_Files is function Lines (This : aliased in out File) return access String_Vector; + procedure Append_Lines (File : Any_Path; + Lines : String_Vector; + Backup : Boolean := True; + Backup_Dir : Any_Path := ""); + -- Add the given lines to the end of the file + private type File (Length, Backup_Len : Natural) is diff --git a/src/alire/alire.ads b/src/alire/alire.ads index cd5d0c78..5c6108dc 100644 --- a/src/alire/alire.ads +++ b/src/alire/alire.ads @@ -9,7 +9,7 @@ with Simple_Logging; package Alire with Preelaborate is - Version : constant String := "1.1.0-dev+branchpins"; + Version : constant String := "1.1.0-dev+pincmdline"; -- 1.1.0-dev: begin post-1.0 changes -- 1.0.0: no changes since rc3 -- 1.0.0-rc3: added help colors PR @@ -97,6 +97,7 @@ package Alire with Preelaborate is function "+" (P : Crate_Name) return String; function "+" (P : String) return Crate_Name; + function To_Name (S : String) return Crate_Name renames "+"; subtype Description_String is String with Dynamic_Predicate => Description_String'Length <= Max_Description_Length; diff --git a/src/alr/alr-commands-init.adb b/src/alr/alr-commands-init.adb index 82290f52..b7593804 100644 --- a/src/alr/alr-commands-init.adb +++ b/src/alr/alr-commands-init.adb @@ -391,7 +391,7 @@ package body Alr.Commands.Init is Alire.Lockfiles.Write ((Solution => Alire.Solutions.Empty_Valid_Solution), Alire.Lockfiles.File_Name - (+Name, String (Filesystem_String'(Directory.Full_Name)))); + (String (Filesystem_String'(Directory.Full_Name)))); Alire.Put_Success (TTY.Emph (Lower_Name) & " initialized successfully."); end Generate; diff --git a/src/alr/alr-commands-pin.adb b/src/alr/alr-commands-pin.adb index 2a91151d..c225e6bd 100644 --- a/src/alr/alr-commands-pin.adb +++ b/src/alr/alr-commands-pin.adb @@ -1,12 +1,10 @@ with Alire.Releases; with Alire.Solutions.Diffs; -with Alire.Pinning; with Alire.URI; with Alire.Utils.TTY; with Alire.Utils.User_Input; with Alr.Commands.User_Input; -with Alr.Platform; with Semantic_Versioning; @@ -52,12 +50,13 @@ package body Alr.Commands.Pin is Cmd.Requires_Full_Index; - Solution := Alire.Pinning.Pin - (Crate => Name, - Version => Version, - Dependencies => Cmd.Root.Release.Dependencies, - Environment => Platform.Properties, - Solution => Solution); + -- To be removed in upcoming PR, kept momentarily for reference + -- Solution := Alire.Pinning.Pin + -- (Crate => Name, + -- Version => Version, + -- Dependencies => Cmd.Root.Release.Dependencies, + -- Environment => Platform.Properties, + -- Solution => Solution); end Pin; @@ -75,11 +74,12 @@ package body Alr.Commands.Pin is Cmd.Requires_Full_Index; - Solution := Alire.Pinning.Unpin - (Crate => Name, - Dependencies => Cmd.Root.Release.Dependencies, - Environment => Platform.Properties, - Solution => Solution); + -- To be removed in upcoming PR, kept momentarily for reference + -- Solution := Alire.Pinning.Unpin + -- (Crate => Name, + -- Dependencies => Cmd.Root.Release.Dependencies, + -- Environment => Platform.Properties, + -- Solution => Solution); end Unpin; begin diff --git a/src/alr/alr-commands-update.adb b/src/alr/alr-commands-update.adb index 55c3c915..71a1f902 100644 --- a/src/alr/alr-commands-update.adb +++ b/src/alr/alr-commands-update.adb @@ -42,7 +42,9 @@ package body Alr.Commands.Update is Cmd.Requires_Full_Index; - Cmd.Root.Update (Parse_Allowed); + Cmd.Root.Update (Parse_Allowed, + Silent => False, + Interact => True); end Execute; ---------------------- diff --git a/src/alr/alr-commands-withing.adb b/src/alr/alr-commands-withing.adb index 3ae29756..8f48b2a8 100644 --- a/src/alr/alr-commands-withing.adb +++ b/src/alr/alr-commands-withing.adb @@ -3,18 +3,13 @@ with Ada.Strings.Fixed; with Ada.Strings.Maps; with Ada.Text_IO; -with Alire.Conditional; -with Alire.Dependencies.Diffs; -with Alire.Index; -with Alire.Manifest; +with Alire.Dependencies; +with Alire.Optional; with Alire.Releases; +with Alire.Roots.Editable; with Alire.Solutions; -with Alire.Solver; with Alire.URI; -with Alire.Utils.User_Input; -with Alr.Commands.Pin; -with Alr.Commands.User_Input; with Alr.OS_Lib; with Alr.Platform; @@ -22,337 +17,38 @@ with Semantic_Versioning.Extended; package body Alr.Commands.Withing is - package Semver renames Semantic_Versioning; - Switch_URL : constant String := "--use"; - procedure Replace_Current - (Cmd : in out Command; - Old_Deps, - New_Deps : Alire.Conditional.Dependencies; - Old_Solution : Alire.Solutions.Solution); - - --------- - -- Add -- - --------- - - function Add (Deps : Alire.Conditional.Dependencies; - New_Dep : String) - return Alire.Conditional.Dependencies - is - use all type Alire.Conditional.Dependencies; - Requested : constant Alire.Dependencies.Dependency := - Alire.Dependencies.From_String (New_Dep); - begin - - -- Check that the requested dependency exists - - if not Alire.Index.Exists (Requested.Crate) then - Trace.Warning - ("The requested crate does not exist in the catalog: " & - (+Requested.Crate)); - end if; - - -- Verify the dependency is truly new - - for Dep of Alire.Conditional.Enumerate (Deps) loop - if Dep.Crate = Requested.Crate then - Trace.Info - ("Not adding " & (+Requested.Crate) - & " because " & Dep.Image & " is already a dependency"); - return Deps; - end if; - end loop; - - -- Merge the dependency. Completeness of the solution will be presented - -- as a whole after all changes have been processed, in Replace_Current. - - return Deps and Alire.Conditional.New_Dependency (Requested.Crate, - Requested.Versions); - end Add; - - ------------------ - -- Add_Softlink -- - ------------------ - - procedure Add_Softlink (Cmd : in out Command; - Dep_Spec : String; - Path : String) is - pragma Unreferenced (Path); - New_Dep : constant Alire.Dependencies.Dependency := - Alire.Dependencies.From_String (Dep_Spec); - begin - -- Confirm target dir - - if not Alire.Utils.User_Input.Approve_Dir (Cmd.URL.all) then - Trace.Info ("Abandoned by user."); - return; - end if; - - -- Prepare new solution - - declare - use Alire; - use type Conditional.Dependencies; - Old_Deps : constant Conditional.Dependencies := - Cmd.Root.Release.Dependencies; - Old_Solution : constant Solutions.Solution := Cmd.Root.Solution; - New_Solution : constant Solutions.Solution := Old_Solution; - -- The following is slated for refactoring in the follow-up PR. Kept - -- momentarily for reference. - -- Old_Solution - -- .Depending_On (New_Dep) - -- .Linking (Crate => New_Dep.Crate, - -- Path => Path); - -- TODO: remove this dead code in PR fixing alr with - begin - - -- Prevent double-add - - if Old_Solution.Depends_On (New_Dep.Crate) then - Reportaise_Wrong_Arguments - ("Not adding " & New_Dep.Crate.TTY_Image & " because " - & Old_Solution.Dependency (New_Dep.Crate).TTY_Image - & " is already a dependency"); - end if; - - -- Report crate detection at target destination - - User_Input.Report_Pinned_Crate_Detection (New_Dep.Crate, - New_Solution); - - -- If we made here there were no errors adding the dependency - -- and storing the softlink. We can proceed to confirming the - -- replacement. - - Replace_Current (Cmd, - Old_Deps => Old_Deps, - New_Deps => Old_Deps and New_Dep, - Old_Solution => New_Solution); - -- We use the New_Solution with the softlink as previous solution, so - -- the pinned directory is used by the solver. - - end; - end Add_Softlink; - - --------------------- - -- Detect_Softlink -- - --------------------- - - procedure Detect_Softlink (Cmd : in out Command; Path : String) is - Root : constant Alire.Roots.Optional.Root := - Alire.Roots.Optional.Detect_Root (Path); - use all type Semver.Point; - begin - if Root.Is_Valid then - if Root.Value.Is_Stored then - -- Add a dependency on ^(detected version) (i.e., safely - -- upgradable) or ~(detected version) (if pre-1.0). - Add_Softlink - (Cmd, - Dep_Spec => Root.Value.Release.Name_Str - & (if Semver.Major (Root.Value.Release.Version) = 0 - then "~" - else "^") - & Root.Value.Release.Version.Image, - Path => Path); - else - Reportaise_Command_Failed - ("cannot add target: " & Root.Value.Storage_Error); - end if; - else - Reportaise_Command_Failed - ("cannot add target: crate metadata not found at " & Path - & " (give an explicit crate name argument to use a plain" - & " GNAT project as dependency)"); - end if; - end Detect_Softlink; - - --------- - -- Del -- - --------- - - function Del (Deps : Alire.Conditional.Dependencies; - Old_Dep : String) - return Alire.Conditional.Dependencies - is - use all type Alire.Conditional.Dependencies; - use all type Semantic_Versioning.Extended.Version_Set; - Requested : constant Alire.Dependencies.Dependency := - Alire.Dependencies.From_String (Old_Dep); - Found : Boolean := False; - begin - if Requested.Versions /= Semantic_Versioning.Extended.Any then - Trace.Warning - ("Version is not used when removing dependencies: " & Old_Dep); - end if; - - -- Iterate over actual dependencies and remove any matching the given - return Filtered : Alire.Conditional.Dependencies do - if Deps.Is_Iterable then - for Dep of Deps loop - if Dep.Is_Value and then Dep.Value.Crate /= Requested.Crate then - -- A regular static dependency - Filtered := Filtered and Dep; - elsif not Dep.Is_Value then - -- Something else (dynamic expression) that we cannot manage - -- programmatically. - Filtered := Filtered and Dep; - Trace.Warning - ("Skipping unsupported conditional dependency: " - & Dep.Image_One_Line); - else - -- Simply don't add the one we want to remove - Found := True; - end if; - end loop; - else - Trace.Warning ("Skipping unsupported conditional dependency: " - & Deps.Image_One_Line); - end if; - - if not Found then - Trace.Warning - ("Crate slated for removal is not among" - & " direct static dependencies: " - & (+Requested.Crate)); - end if; - end return; - end Del; - - --------------------- - -- Replace_Current -- - --------------------- - - procedure Replace_Current - (Cmd : in out Command; - Old_Deps, - New_Deps : Alire.Conditional.Dependencies; - Old_Solution : Alire.Solutions.Solution) - is - begin - Cmd.Requires_Full_Index; - - -- Set, regenerate and update - declare - New_Root : constant Alire.Roots.Root := - Alire.Roots.New_Root - (Cmd.Root.Release.Replacing (Dependencies => New_Deps), - Cmd.Root.Path, - Platform.Properties); - New_Solution : constant Alire.Solutions.Solution := - Alire.Solver.Resolve - (New_Deps, - Platform.Properties, - Old_Solution, - Options => (Age => Query_Policy, - others => <>)); - - Deps_Diff : constant Alire.Dependencies.Diffs.Diff := - Alire.Dependencies.Diffs.Between - (Old_Deps, - Alire.Solutions.Restrict_New_Dependencies - (Old_Deps, - New_Deps, - New_Solution)); - - use Alire.Utils.User_Input; - begin - - -- First of all, warn about dubious caret - - if New_Root.Release.Check_Caret_Warning and then - Query - (Question => "Do you want to continue with that dependency?", - Valid => (Yes | No => True, others => False), - Default => No) = No - then - Reportaise_Command_Failed ("Abandoned by user"); - end if; - - -- Show changes to apply - - Trace.Info ("Requested changes:"); - Trace.Info (""); - Deps_Diff.Print; - - -- Show the effects on the solution - - if not Alire.Utils.User_Input.Confirm_Solution_Changes - (Cmd.Root.Solution.Changes (New_Solution), - Changed_Only => not Alire.Detailed) - then - Trace.Info ("No changes applied."); - return; - end if; - - -- Add changes to the manifest: - - Alire.Manifest.Append (Cmd.Root.Crate_File, - Deps_Diff.Added); - Alire.Manifest.Remove (Cmd.Root.Crate_File, - Deps_Diff.Removed); - Trace.Detail ("Manifest updated, fetching dependencies now"); - - -- And apply changes (will also generate new lockfile) - - Cmd.Set (New_Root); - Cmd.Root.Set (Solution => New_Solution); - Cmd.Root.Deploy_Dependencies; - end; - - end Replace_Current; - --------- -- Add -- --------- - procedure Add (Cmd : in out Command) is - Old_Deps : constant Alire.Conditional.Dependencies := - Cmd.Root.Release.Dependencies; - New_Deps : Alire.Conditional.Dependencies := Old_Deps; - use type Alire.Conditional.Dependencies; + procedure Add (Root : in out Alire.Roots.Editable.Root) is begin for I in 1 .. Num_Arguments loop - New_Deps := Add (New_Deps, Argument (I)); + Root.Add_Dependency (Alire.Dependencies.From_String (Argument (I))); end loop; - - if Old_Deps /= New_Deps then - Cmd.Replace_Current (Old_Deps, New_Deps, Cmd.Root.Solution); - end if; end Add; --------- -- Del -- --------- - procedure Del (Cmd : in out Command) is - Old_Deps : constant Alire.Conditional.Dependencies := - Cmd.Root.Release.Dependencies; - New_Deps : Alire.Conditional.Dependencies := Old_Deps; - use type Alire.Conditional.Dependencies; + procedure Del (Root : in out Alire.Roots.Editable.Root) is begin for I in 1 .. Num_Arguments loop - New_Deps := Del (New_Deps, Argument (I)); + Root.Remove_Dependency (Alire.To_Name (Argument (I))); end loop; - - if Old_Deps /= New_Deps then - Cmd.Replace_Current (Old_Deps, New_Deps, Cmd.Root.Solution); - else - Trace.Warning ("There are no changes to apply."); - end if; end Del; ---------- -- From -- ---------- - procedure From (Cmd : in out Command) is + procedure From (Root : in out Alire.Roots.Editable.Root) is use Ada.Text_IO; use Utils; - Deps : Alire.Conditional.Dependencies; - ------------- -- Extract -- ------------- @@ -390,7 +86,8 @@ package body Alr.Commands.Withing is Found := Withh; end if; when Withh => - Deps := Add (Deps, Line (First .. Last)); + Root.Add_Dependency + (Alire.Dependencies.From_String (Line (First .. Last))); end case; exit when Last = Line'Last; @@ -429,15 +126,6 @@ package body Alr.Commands.Withing is for I in 1 .. Num_Arguments loop Check_File (Argument (I)); end loop; - - if not Deps.Is_Empty then - Cmd.Replace_Current - (Old_Deps => Alire.Conditional.No_Dependencies, - New_Deps => Deps, - Old_Solution => Alire.Solutions.Empty_Valid_Solution); - else - Trace.Warning ("No dependencies found."); - end if; end From; ---------- @@ -463,6 +151,59 @@ package body Alr.Commands.Withing is end if; end List; + ------------------ + -- Add_With_Pin -- + ------------------ + + procedure Add_With_Pin (Cmd : Command; + Root : in out Alire.Roots.Editable.Root) + is + Crate : constant Alire.Optional.Crate_Name := + (if Num_Arguments = 1 + then Alire.Optional.Crate_Names.Unit + (Alire.Dependencies.From_String (Argument (1)).Crate) + else Alire.Optional.Crate_Names.Empty); + begin + + -- First, add the dependency if given + + if Num_Arguments = 1 then + declare + use type Semantic_Versioning.Extended.Version_Set; + Dep : constant Alire.Dependencies.Dependency := + Alire.Dependencies.From_String (Argument (1)); + begin + if Dep.Versions /= Semantic_Versioning.Extended.Any then + Root.Add_Dependency (Dep); + end if; + end; + end if; + + -- Now, add the pin to the path/remote + + if Cmd.Commit.all /= "" + or else Alire.URI.Is_HTTP_Or_Git (Cmd.URL.all) + then + + -- Pin to remote repo, with optional dependency first + + Root.Add_Remote_Pin + (Crate => Crate, + Origin => Cmd.URL.all, + Commit => Cmd.Commit.all, + Branch => ""); -- TODO: PARSE BRANCH + + else + + -- Pin to local folder + + Root.Add_Path_Pin + (Crate => Crate, + Path => Cmd.URL.all); + + end if; + end Add_With_Pin; + ------------- -- Execute -- ------------- @@ -525,53 +266,39 @@ package body Alr.Commands.Withing is end if; end if; - if not (Cmd.Del or else Cmd.From) then - - -- Must be Add, but it could be regular or softlink + -- At this point, we are modifying the manifest to incorporate changes, + -- so we create a temporary copy of the root for these changes - if Cmd.URL.all /= "" then - Pin.Warn_Manual_Only; - - if Cmd.Commit.all /= "" - or else Alire.URI.Is_HTTP_Or_Git (Cmd.URL.all) - then - - -- Pin to remote repo + declare + New_Root : Alire.Roots.Editable.Root := + Alire.Roots.Editable.New_Root (Cmd.Root); + begin - null; + if not (Cmd.Del or else Cmd.From) then - -- Slated for immediate removal; kept momentarily for reference - -- Add_Remote_Link (Cmd, - -- Dep => (if Num_Arguments = 1 - -- then Argument (1) - -- else "")); + -- Must be Add, but it could be regular or softlink + if Cmd.URL.all /= "" then + Cmd.Add_With_Pin (New_Root); else - - -- Pin to local folder - - if Num_Arguments = 1 then - Add_Softlink (Cmd, - Dep_Spec => Argument (1), - Path => Cmd.URL.all); - else - Detect_Softlink (Cmd, - Cmd.URL.all); - end if; + Cmd.Requires_Full_Index; + Add (New_Root); end if; - else + + elsif Cmd.Del then + Del (New_Root); + elsif Cmd.From then Cmd.Requires_Full_Index; - Cmd.Add; + From (New_Root); + else + raise Program_Error with "List should have already happened"; end if; - elsif Cmd.Del then - Del (Cmd); - elsif Cmd.From then - Cmd.Requires_Full_Index; - From (Cmd); - else - raise Program_Error with "List should have already happened"; - end if; + -- Apply changes + + New_Root.Confirm_And_Commit; + + end; end Execute; ---------------------- diff --git a/src/alr/alr-commands.adb b/src/alr/alr-commands.adb index 6fd2696e..fa928b16 100644 --- a/src/alr/alr-commands.adb +++ b/src/alr/alr-commands.adb @@ -595,7 +595,8 @@ package body Alr.Commands is if Checked.Solution.Is_Attempted then -- Check deps on disk match those in lockfile Cmd.Requires_Full_Index (Strict => False); - Checked.Sync_From_Manifest (Silent => True); + Checked.Sync_From_Manifest (Silent => False, + Interact => False); return; end if; @@ -647,7 +648,9 @@ package body Alr.Commands is if Sync then Cmd.Requires_Full_Index (Strict => False); - Checked.Sync_From_Manifest (Silent => True, Force => True); + Checked.Sync_From_Manifest (Silent => False, + Interact => False, + Force => True); -- As we just created the empty lockfile, we force the update end if; end; diff --git a/testsuite/disabled/with/changes-info/test.py b/testsuite/disabled/with/changes-info/test.py index 34b0adf8..84e9cf51 100644 --- a/testsuite/disabled/with/changes-info/test.py +++ b/testsuite/disabled/with/changes-info/test.py @@ -40,8 +40,9 @@ Changes to dependency solution: p.out, flags=re.S) ############################################################################### -# Check adding a pinned dir -p = run_alr('with', 'local_crate', '--use=/', quiet=False) +# Check adding a pinned dir (the dir must exist) +os.mkdir("local_crate") +p = run_alr('with', 'local_crate', '--use=local_crate', quiet=False) assert_match(".*" + re.escape("""Requested changes: @@ -49,7 +50,7 @@ assert_match(".*" + Changes to dependency solution: - +· local_crate unknown (new,pin=""") + ".*", # skip platform-dependent path + +· local_crate unknown (new,path=local_crate)""") + ".*", p.out, flags=re.S) ############################################################################### diff --git a/testsuite/disabled/with/pin-dir/test.py b/testsuite/disabled/with/pin-dir/test.py index 4dbaef7b..2ea2c9a0 100644 --- a/testsuite/disabled/with/pin-dir/test.py +++ b/testsuite/disabled/with/pin-dir/test.py @@ -28,11 +28,9 @@ run_alr('build') p = run_alr('with', '--solve') # For this match we don't know where the test is temporarily put, so we skip # over some parts of the output -s = re.escape(dir_separator()) # platform-dependent assert_match('.*Dependencies \(external\):.*' - 'libhello\* \(direct,linked' - ',pin=.*' + s + 'my_index' + s + - 'crates' + s + 'libhello_1.0.0\).*', + 'libhello\^1\.0\.0 \(direct,linked' + ',path=.*/my_index/crates/libhello_1.0.0\).*', p.out, flags=re.S) # Check that removing the dependency works and build is again failing diff --git a/testsuite/disabled/with/pin-transitive/test.py b/testsuite/disabled/with/pin-transitive/test.py index 69f7a1a0..64342824 100644 --- a/testsuite/disabled/with/pin-transitive/test.py +++ b/testsuite/disabled/with/pin-transitive/test.py @@ -25,12 +25,10 @@ os.chdir("nest") init_local_crate(name="base") run_alr("with", "--use=../../direct") -s = os.sep - # Verify created pins p = run_alr("pin") -assert_eq("direct file:.." + s + ".." + s + "direct \n" - "indirect file:.." + s + ".." + s + "indirect \n", +assert_eq("direct file:../../direct \n" + "indirect file:../../indirect \n", p.out) # Check pin removal @@ -40,7 +38,7 @@ os.chdir("../nest/base") run_alr("update") p = run_alr("pin") -assert_eq("direct file:.." + s + ".." + s + "direct \n", +assert_eq("direct file:../../direct \n", p.out) diff --git a/testsuite/tests/with/dynamic-dependencies/test.py b/testsuite/tests/with/dynamic-dependencies/test.py index e1d11ca4..eb28005f 100644 --- a/testsuite/tests/with/dynamic-dependencies/test.py +++ b/testsuite/tests/with/dynamic-dependencies/test.py @@ -44,9 +44,6 @@ p = run_alr('with', '--del', 'superhello', complain_on_error=False, quiet=False) assert_match(".*" + - re.escape("Skipping unsupported conditional dependency: " - "(case OS is others => superhello*)") + - ".*" + re.escape("Crate slated for removal is not among" " direct static dependencies: superhello") + ".*", diff --git a/testsuite/tests/with/no-double-add/test.py b/testsuite/tests/with/no-double-add/test.py index c0773691..a2012bee 100644 --- a/testsuite/tests/with/no-double-add/test.py +++ b/testsuite/tests/with/no-double-add/test.py @@ -12,10 +12,10 @@ from drivers.asserts import assert_eq p = run_alr('init', '--bin', 'xxx') os.chdir('xxx') p = run_alr('with', 'libhello') -p = run_alr('with', 'libhello', quiet=False) +p = run_alr('with', 'libhello', quiet=False, complain_on_error=False) assert_eq( - 'Not adding libhello because libhello^1.0.0 is already a dependency\n', + 'ERROR: libhello is already a direct dependency.\n', p.out) print('SUCCESS') diff --git a/testsuite/disabled/with/pin-dir-crate-autodetect/test.py b/testsuite/tests/with/pin-dir-crate-autodetect/test.py similarity index 100% rename from testsuite/disabled/with/pin-dir-crate-autodetect/test.py rename to testsuite/tests/with/pin-dir-crate-autodetect/test.py diff --git a/testsuite/disabled/with/pin-dir-crate-autodetect/test.yaml b/testsuite/tests/with/pin-dir-crate-autodetect/test.yaml similarity index 100% rename from testsuite/disabled/with/pin-dir-crate-autodetect/test.yaml rename to testsuite/tests/with/pin-dir-crate-autodetect/test.yaml diff --git a/testsuite/disabled/with/pin-dir-crate/test.py b/testsuite/tests/with/pin-dir-crate/test.py similarity index 100% rename from testsuite/disabled/with/pin-dir-crate/test.py rename to testsuite/tests/with/pin-dir-crate/test.py diff --git a/testsuite/disabled/with/pin-dir-crate/test.yaml b/testsuite/tests/with/pin-dir-crate/test.yaml similarity index 100% rename from testsuite/disabled/with/pin-dir-crate/test.yaml rename to testsuite/tests/with/pin-dir-crate/test.yaml diff --git a/testsuite/disabled/with/pin-dir-mismatch/test.py b/testsuite/tests/with/pin-dir-mismatch/test.py similarity index 100% rename from testsuite/disabled/with/pin-dir-mismatch/test.py rename to testsuite/tests/with/pin-dir-mismatch/test.py diff --git a/testsuite/disabled/with/pin-dir-mismatch/test.yaml b/testsuite/tests/with/pin-dir-mismatch/test.yaml similarity index 100% rename from testsuite/disabled/with/pin-dir-mismatch/test.yaml rename to testsuite/tests/with/pin-dir-mismatch/test.yaml diff --git a/testsuite/disabled/with/tree-switch/test.py b/testsuite/tests/with/tree-switch/test.py similarity index 86% rename from testsuite/disabled/with/tree-switch/test.py rename to testsuite/tests/with/tree-switch/test.py index 2ea7ff88..c0741d50 100644 --- a/testsuite/disabled/with/tree-switch/test.py +++ b/testsuite/tests/with/tree-switch/test.py @@ -21,7 +21,8 @@ run_alr('with', 'hello^1') run_alr('with', 'superhello') # Add more dependencies, without a proper release -run_alr('with', 'wip', '--use', '/fake', '--force') # force bc dir is missing +os.mkdir("fake") +run_alr('with', 'wip', '--use', 'fake', '--force') # force bc dir is missing run_alr('with', 'unobtanium', '--force') # Verify printout (but for test-dependent path) @@ -33,7 +34,7 @@ assert_match(re.escape('''xxx=0.0.0 +-- superhello=1.0.0 (^1.0.0) | +-- libhello=1.0.1 (~1.0) +-- unobtanium* (direct,missed) (*) -+-- wip* (direct,linked,pin=''') + '.*' + re.escape(') (*)'), ++-- wip* (direct,linked,path=''') + '.*' + re.escape(') (*)'), p.out, flags=re.S) print('SUCCESS') diff --git a/testsuite/disabled/with/tree-switch/test.yaml b/testsuite/tests/with/tree-switch/test.yaml similarity index 100% rename from testsuite/disabled/with/tree-switch/test.yaml rename to testsuite/tests/with/tree-switch/test.yaml diff --git a/testsuite/disabled/with/versions-switch/test.py b/testsuite/tests/with/versions-switch/test.py similarity index 95% rename from testsuite/disabled/with/versions-switch/test.py rename to testsuite/tests/with/versions-switch/test.py index ecd5a52e..95889da5 100644 --- a/testsuite/disabled/with/versions-switch/test.py +++ b/testsuite/tests/with/versions-switch/test.py @@ -21,7 +21,8 @@ run_alr('with', 'hello^1') run_alr('with', 'superhello') # Add a pinned directory and a missing dependency -run_alr('with', 'wip', '--use', '/fake') +os.mkdir("fake") +run_alr('with', 'wip', '--use', 'fake') run_alr('with', 'unobtanium', '--force') # Check output diff --git a/testsuite/disabled/with/versions-switch/test.yaml b/testsuite/tests/with/versions-switch/test.yaml similarity index 100% rename from testsuite/disabled/with/versions-switch/test.yaml rename to testsuite/tests/with/versions-switch/test.yaml -- 2.39.5