From 30908899f6d2b37364808fd3d469c974cb059378 Mon Sep 17 00:00:00 2001 From: Alejandro R Mosteo Date: Wed, 3 Mar 2021 16:54:48 +0100 Subject: [PATCH] Add `alr publish --manifest ` variant (#635) * alire.ads: bump version to 1.1.0-dev * user-changes.md: add header for 1.1 * Publish: --manifest working for git remotes * Publish: --manifest working for --tar releases * Testsuite: publish --manifest variants * Updated documentation * CI-found fixes * Rebase tweaks and bumped version * user-changes.md: move log entry to 1.1 section * publishing.md: Reword explanation of --manifest --- doc/publishing.md | 20 +- doc/user-changes.md | 12 + scripts/alr-completion.bash | 11 +- src/alire/alire-publish.adb | 468 +++++++++++------- src/alire/alire-publish.ads | 28 +- src/alr/alr-commands-publish.adb | 19 +- src/alr/alr-commands-publish.ads | 9 +- testsuite/fix-versions.sh | 2 +- .../tests/publish/local-repo-nonstd/test.py | 52 ++ .../tests/publish/local-repo-nonstd/test.yaml | 4 + .../publish/remote-origin-nonstd/test.py | 64 +++ .../publish/remote-origin-nonstd/test.yaml | 1 + .../my_index/crates/crate/alire.toml | 10 + .../my_index/crates/crate/crate.gpr | 22 + .../my_index/crates/crate/src/crate.adb | 3 + .../my_index/index/cr/crate/crate-1.0.0.toml | 13 + .../my_index/index/index.toml | 1 + .../publish/tarball-plaindir-nonstd/test.py | 56 +++ .../publish/tarball-plaindir-nonstd/test.yaml | 4 + .../my_index/crates/crate/alire.toml | 10 + .../my_index/crates/crate/crate.gpr | 22 + .../my_index/crates/crate/src/crate.adb | 3 + .../my_index/index/cr/crate/crate-1.0.0.toml | 13 + .../my_index/index/index.toml | 1 + .../tests/publish/tarball-repo-nonstd/test.py | 45 ++ .../publish/tarball-repo-nonstd/test.yaml | 4 + 26 files changed, 714 insertions(+), 183 deletions(-) create mode 100644 testsuite/tests/publish/local-repo-nonstd/test.py create mode 100644 testsuite/tests/publish/local-repo-nonstd/test.yaml create mode 100644 testsuite/tests/publish/remote-origin-nonstd/test.py create mode 100644 testsuite/tests/publish/remote-origin-nonstd/test.yaml create mode 100644 testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/alire.toml create mode 100644 testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/crate.gpr create mode 100644 testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/src/crate.adb create mode 100644 testsuite/tests/publish/tarball-plaindir-nonstd/my_index/index/cr/crate/crate-1.0.0.toml create mode 100644 testsuite/tests/publish/tarball-plaindir-nonstd/my_index/index/index.toml create mode 100644 testsuite/tests/publish/tarball-plaindir-nonstd/test.py create mode 100644 testsuite/tests/publish/tarball-plaindir-nonstd/test.yaml create mode 100644 testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/alire.toml create mode 100644 testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/crate.gpr create mode 100644 testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/src/crate.adb create mode 100644 testsuite/tests/publish/tarball-repo-nonstd/my_index/index/cr/crate/crate-1.0.0.toml create mode 100644 testsuite/tests/publish/tarball-repo-nonstd/my_index/index/index.toml create mode 100644 testsuite/tests/publish/tarball-repo-nonstd/test.py create mode 100644 testsuite/tests/publish/tarball-repo-nonstd/test.yaml diff --git a/doc/publishing.md b/doc/publishing.md index 6127d59c..600e64bd 100644 --- a/doc/publishing.md +++ b/doc/publishing.md @@ -180,8 +180,24 @@ assistant will resume as if it had been invoked with `alr publish ` In case your project does not easily map to a single Alire crate (e.g., because you manage multiple project files with different dependencies, or there are other reasons to keep the sources together even if they generate several -crates), you will need to prepare individual online source archives (or -repositories) and proceed from there. +crates), you have several options. + +The simplest one would be to make each crate a subdirectory within the +repository, with its corresponding Alire manifest, sources and project files. +Then, you can use `alr publish --tar` normally inside each subdirectory. + +Another possibility would be to use a bit of scripting to create temporary +subfolders with the described organization, and again using `alr publish --tar` +normally. + +Finally, the `alr publish` command provides a `--manifest ` switch to +work in place with several crates. You can have different manifests at custom +locations (other than the expected `./alire.toml`) and provide each one in turn +with the `--manifest` switch to create their respective crate. In this case, +`alr` temporarily uses the given file as the root manifest, so all sources will +be packaged for each crate. This is a bit wasteful, but as long as each crate's +project files are properly defined (no shared sources), this remains an option +to split the sources into crates. ### Starting from other configurations diff --git a/doc/user-changes.md b/doc/user-changes.md index 889145c9..f98e8e5b 100644 --- a/doc/user-changes.md +++ b/doc/user-changes.md @@ -6,6 +6,18 @@ stay on top of `alr` new features. ## Release `1.1` +### Switch to help with publishing of multi-crate repositories + +PR [#635](https://github.com/alire-project/alire/pull/635). + +The `alr publish` command now supports a new `--manifest ` switch, to +help with packaging sources that provide several crates. Maintainers can now +prepare different manifest files for the corresponding crates, and select each +one in turn for publishing, without the repository itself being an actual Alire +crate. Source management must still be taken care of by maintainers; sources +should not be shared by project files in different crates intended to be +simultaneously included. + ### Configuration of crates PR [#699](https://github.com/alire-project/alire/pull/679). diff --git a/scripts/alr-completion.bash b/scripts/alr-completion.bash index 9ed8633c..990b34d1 100755 --- a/scripts/alr-completion.bash +++ b/scripts/alr-completion.bash @@ -34,7 +34,7 @@ function _alr_completion() { # When no command found, suggest commands and long global switches. # Although global switches can be used even after the command is given, by # hidding them after the command we obtain clearer command-specific - # suggestions. + # suggestions. $found || COMPREPLY+=($(compgen -W "$_alr_commands $_alr_global_switches" -- $curr)) # When command found, always add the compatible command switches @@ -56,6 +56,11 @@ function _alr_completion() { [ "$prev" == "--add" ] && compopt -o dirnames ;; + publish) + # Suggest files when using a non-standard manifest + [ "$prev" == "--manifest" ] && compopt -o filenames + ;; + run) # Suggest only the executables explicitly declared by the release COMPREPLY+=($(compgen -W "$(alr run --list |\ @@ -63,7 +68,7 @@ function _alr_completion() { tail -n +2 |\ awk '{print $1}')" -- $curr)) ;; - + with) # When the previous word is "with", show any crate: [ "$prev" == "with" ] && COMPREPLY+=($(compgen -W "$_alr_crates" -- $curr)) @@ -71,7 +76,7 @@ function _alr_completion() { [ "$prev" == "--del" ] && COMPREPLY+=($(compgen -W "$(alr with | tail +2 | grep -Eo -- '[_a-z0-9]+')" -- $curr)) ;; esac -} +} # Bind the function that performs context-aware completion complete -F _alr_completion alr diff --git a/src/alire/alire-publish.adb b/src/alire/alire-publish.adb index fee98c69..95386cf2 100644 --- a/src/alire/alire-publish.adb +++ b/src/alire/alire-publish.adb @@ -51,16 +51,54 @@ package body Alire.Publish is Origin : Origins.Origin := Origins.New_External ("undefined"); -- We use external as "undefined" until a proper origin is provided. + Path : UString := +"."; + -- Where to find the local workspace + Revision : UString := +"HEAD"; -- A particular revision for publishing from a git repo - Root : Roots.Optional.Root; - -- Some steps require or can use a detected root - Tmp_Deploy_Dir : Directories.Temp_File; -- Place to check the sources end record; + --------------- + -- Base_Path -- + --------------- + -- The workspace root path. To support out-of-alire packaging, this + -- defaults to the current directory when using a nonstandard manifest. + function Base_Path (This : Data) return Any_Path + is (if This.Options.Nonstandard_Manifest + then +This.Path + else Root.Current.Path); + + ----------------------- + -- Starting_Manifest -- + ----------------------- + -- The initial manifest in the workspace, at the standard location, or + -- overriden to be taken from somewhere else. + function Starting_Manifest (This : Data) return Any_Path + is (if This.Options.Nonstandard_Manifest + then This.Options.Manifest + else Root.Current.Path / Roots.Crate_File_Name); + + ----------------------- + -- Packaged_Manifest -- + ----------------------- + -- The manifest that we have in tmp folder during verification. This is + -- always named and placed at the expected location. + function Packaged_Manifest (This : Data) return Any_Path + is (This.Tmp_Deploy_Dir.Filename / Roots.Crate_File_Name); + + ----------------- + -- New_Options -- + ----------------- + + function New_Options (Skip_Build : Boolean := False; + Manifest : String := Roots.Crate_File_Name) + return All_Options + is (Manifest_File => +Manifest, + Skip_Build => Skip_Build); + --------------- -- Git_Error -- --------------- @@ -105,6 +143,89 @@ package body Alire.Publish is end case; end Check_Git_Clean; + ------------------- + -- Check_Release -- + ------------------- + -- Checks the presence of recommended/mandatory fileds in the release + procedure Check_Release (Release : Releases.Release) is + use Utils.User_Input; + + Recommend : Utils.String_Vector; -- Optional + Missing : Utils.String_Vector; -- Mandatory + + Caret_Pre_1 : Boolean := False; -- To warn about this + + function Tomify (S : String) return String renames TOML_Adapters.Tomify; + begin + + -- Check not duplicated + + Features.Index.Setup_And_Load (From => Config.Edit.Indexes_Directory); + if Index.Exists (Release.Name, Release.Version) then + Raise_Checked_Error + ("Target release " & Release.Milestone.TTY_Image + & " already exist in a loaded index"); + end if; + + -- Present release information to user + + Ada.Text_IO.New_Line; + Trace.Info ("The release to be published contains this information:"); + Ada.Text_IO.New_Line; + Release.Print; + + -- Detect missing recommended fields + + for Key in Properties.From_TOML.Recommended'Range loop + if Properties.From_TOML.Recommended (Key) then + if not Release.Has_Property (Tomify (Key'Image)) then + Recommend.Append (Tomify (Key'Image)); + end if; + end if; + end loop; + + if not Recommend.Is_Empty then + Ada.Text_IO.New_Line; + Trace.Warning ("Missing optional recommended properties: " + & TTY.Warn (Recommend.Flatten (", "))); + end if; + + -- Detect missing mandatory. This isn't detected by the TOML + -- deserialization because we are still relying on the user manifest + -- (the index one isn't generated until the user gives the go-ahead). + + for Key in Properties.From_TOML.Mandatory'Range (2) loop + if Properties.From_TOML.Mandatory (Crates.Index_Release, Key) then + if not Release.Has_Property (Tomify (Key'Image)) then + Missing.Append (Tomify (Key'Image)); + end if; + end if; + end loop; + + Caret_Pre_1 := Release.Check_Caret_Warning; + + if not Missing.Is_Empty then + Ada.Text_IO.New_Line; + Raise_Checked_Error ("Missing required properties: " + & TTY.Error (Missing.Flatten (", "))); + end if; + + -- Final confirmation. We default to Yes if no recommended missing or + -- Force. + + Ada.Text_IO.New_Line; + if Utils.User_Input.Query + ("Do you want to proceed with this information?", + Valid => (Yes | No => True, others => False), + Default => (if Force or else + (Recommend.Is_Empty and then not Caret_Pre_1) + then Yes + else No)) /= Yes + then + Raise_Checked_Error ("Abandoned by user"); + end if; + end Check_Release; + ----------------- -- STEP BODIES -- ----------------- @@ -126,7 +247,7 @@ package body Alire.Publish is procedure Check_Build (Context : in out Data) is -- Enter the temporary as if it were a workspace (which it has to -- be, as it contains the user manifest). Auto-update should retrieve - -- dependencies, and since we are not repacking, there's no problem + -- dependencies, and since we are not repackaging, there's no problem -- with altering contents under alire or regenerating the lock file. Guard : Directories.Guard (Directories.Enter (Context.Tmp_Deploy_Dir.Filename)) @@ -154,6 +275,40 @@ package body Alire.Publish is Log_Success ("Build succeeded."); end Check_Build; + ------------------------- + -- Check_User_Manifest -- + ------------------------- + -- Ensure that we are at a valid root, or else that the nonstadard manifest + -- file is loadable. Either way, the contents of the release described by + -- the manifest are vetted for completeness. + procedure Check_User_Manifest (Context : in out Data) is + use all type Roots.Optional.States; + begin + if Context.Options.Nonstandard_Manifest then + Check_Release (Releases.From_Manifest + (Starting_Manifest (Context), + Alire.Manifest.Local)); + -- Will have raised if the release is not loadable or incomplete + else + declare + Root : constant Roots.Optional.Root := Alire.Root.Current; + begin + case Root.Status is + when Outside => + Raise_Checked_Error + ("No Alire workspace found at current location"); + when Broken => + Raise_Checked_Error + (Errors.Wrap + ("Invalid metadata found at " & Root.Value.Path, + Root.Brokenness)); + when Valid => + Check_Release (Root.Value.Release); + end case; + end; + end if; + end Check_User_Manifest; + -------------------- -- Deploy_Sources -- -------------------- @@ -170,7 +325,7 @@ package body Alire.Publish is -- Obtain source archive (or no-op for repositories): - Deployer.Fetch (Context.Tmp_Deploy_Dir.Filename).Assert; + Deployer.Fetch (Context.Tmp_Deploy_Dir.Filename).Assert; -- Compute hashes in supported origin kinds (e.g. source archives) @@ -196,11 +351,21 @@ package body Alire.Publish is -- Check that the maintainer's manifest is at the expected location if not GNAT.OS_Lib.Is_Regular_File - (Context.Tmp_Deploy_Dir.Filename / Roots.Crate_File_Name) + (Context.Tmp_Deploy_Dir.Filename / Context.Options.Manifest) then Raise_Checked_Error ("Remote sources are missing the '" - & Roots.Crate_File_Name & "' manifest file."); + & Context.Options.Manifest & "' manifest file."); + end if; + + -- For a non-standard manifest, move it in place (akin to how `alr get` + -- will regenerate it from the index). Subsequent tests can then assume + -- a regularly deployed crate. + + if Context.Options.Nonstandard_Manifest then + Ada.Directories.Copy_File + (Context.Tmp_Deploy_Dir.Filename / Context.Options.Manifest, + Context.Tmp_Deploy_Dir.Filename / Roots.Crate_File_Name); end if; end Deploy_Sources; @@ -215,8 +380,7 @@ package body Alire.Publish is -- manifest. procedure Generate_Index_Manifest (Context : in out Data) is - User_Manifest : constant Any_Path := - Context.Tmp_Deploy_Dir.Filename / Roots.Crate_File_Name; + User_Manifest : constant Any_Path := Packaged_Manifest (Context); Workspace : constant Roots.Optional.Root := Root.Current; begin if not GNAT.OS_Lib.Is_Read_Accessible_File (User_Manifest) then @@ -246,6 +410,7 @@ package body Alire.Publish is Index_File : File_Type; begin if Workspace.Is_Valid and then + (not Context.Options.Nonstandard_Manifest) and then Workspace.Value.Release.Name /= Name then Raise_Checked_Error @@ -311,7 +476,8 @@ package body Alire.Publish is --------------------- procedure Prepare_Archive (Context : in out Data) with - Pre => Context.Root.Is_Valid; + Pre => Alire.Manifest.Is_Valid (Context.Options.Manifest, + Alire.Manifest.Local); -- Prepare a tar file either using git archive (if git repo detected) or -- plain tar otherwise. @@ -319,13 +485,15 @@ package body Alire.Publish is use Utils; Target_Dir : constant Relative_Path := Paths.Working_Folder_Inside_Root / "archives"; - Root : Roots.Root renames Context.Root.Value; + Release : constant Releases.Release := + Releases.From_Manifest (Context.Options.Manifest, + Alire.Manifest.Local); Milestone : constant String := - TOML_Index.Manifest_File (Root.Release.Name, - Root.Release.Version, + TOML_Index.Manifest_File (Release.Name, + Release.Version, With_Extension => False); Git : constant VCSs.Git.VCS := VCSs.Git.Handler; - Is_Repo : constant Boolean := Git.Is_Repository (Root.Path); + Is_Repo : constant Boolean := Git.Is_Repository (Base_Path (Context)); Archive : constant Relative_Path := Target_Dir / (Milestone @@ -392,7 +560,7 @@ package body Alire.Publish is begin if Is_Repo then - Check_Git_Clean (Root.Path, For_Archiving => True); + Check_Git_Clean (Base_Path (Context), For_Archiving => True); else Trace.Warning ("Not in a git repository, assuming plain sources."); end if; @@ -424,7 +592,7 @@ package body Alire.Publish is Trace.Always ("The URL is: " & TTY.URL (Remote_URL)); Context.Origin := Origins.New_Source_Archive - (Remote_URL, + (Utils.Trim (Remote_URL), -- remove unwanted extra whitespaces Ada.Directories.Simple_Name (Archive)); -- This origin creation may raise if URL is improper @@ -483,85 +651,11 @@ package body Alire.Publish is Release : constant Releases.Release := Releases .From_Manifest - (Context.Tmp_Deploy_Dir.Filename / Roots.Crate_File_Name, - Manifest.Local) + (Packaged_Manifest (Context), + Alire.Manifest.Local) .Replacing (Origin => Context.Origin); - use all type Utils.User_Input.Answer_Kind; - - Recommend : Utils.String_Vector; -- Optional - Missing : Utils.String_Vector; -- Mandatory - - Caret_Pre_1 : Boolean := False; -- To warn about this - - function Tomify (S : String) return String renames TOML_Adapters.Tomify; begin - - -- Check not duplicated - - Features.Index.Setup_And_Load (From => Config.Edit.Indexes_Directory); - if Index.Exists (Release.Name, Release.Version) then - Raise_Checked_Error - ("Target release " & Release.Milestone.TTY_Image - & " already exist in a loaded index"); - end if; - - -- Present release information - - Ada.Text_IO.New_Line; - Trace.Info ("The release to be published contains this information:"); - Ada.Text_IO.New_Line; - Release.Print; - - -- Detect missing recommended fields - - for Key in Properties.From_TOML.Recommended'Range loop - if Properties.From_TOML.Recommended (Key) then - if not Release.Has_Property (Tomify (Key'Image)) then - Recommend.Append (Tomify (Key'Image)); - end if; - end if; - end loop; - - if not Recommend.Is_Empty then - Ada.Text_IO.New_Line; - Trace.Warning ("Missing optional recommended properties: " - & TTY.Warn (Recommend.Flatten (", "))); - end if; - - -- Detect missing mandatory. This isn't detected by the TOML - -- deserialization because we are still relying on the user manifest - -- (the index one isn't generated until the user gives the go-ahead). - - for Key in Properties.From_TOML.Mandatory'Range (2) loop - if Properties.From_TOML.Mandatory (Crates.Index_Release, Key) then - if not Release.Has_Property (Tomify (Key'Image)) then - Missing.Append (Tomify (Key'Image)); - end if; - end if; - end loop; - - Caret_Pre_1 := Release.Check_Caret_Warning; - - if not Missing.Is_Empty then - Ada.Text_IO.New_Line; - Raise_Checked_Error ("Missing required properties: " - & TTY.Error (Missing.Flatten (", "))); - end if; - - -- Final confirmation. We default to Yes if no recommended missing or - -- Force. - - Ada.Text_IO.New_Line; - if Utils.User_Input.Query - ("Do you want to proceed with this information?", - Valid => (Yes | No => True, others => False), - Default => (if Force or else - (Recommend.Is_Empty and then not Caret_Pre_1) - then Yes - else No)) /= Yes - then - Raise_Checked_Error ("Abandoned by user"); - end if; + Check_Release (Release); end Show_And_Confirm; ------------------- @@ -695,9 +789,10 @@ package body Alire.Publish is -- STEPS SCAFFOLDING -- ----------------------- - -- Step names must be in order of execution: + -- Any sequence of steps can be selected by creating an array of step names type Step_Names is - (Step_Prepare_Archive, + (Step_Check_User_Manifest, + Step_Prepare_Archive, Step_Verify_Origin, Step_Verify_Github, Step_Deploy_Sources, @@ -705,17 +800,22 @@ package body Alire.Publish is Step_Show_And_Confirm, Step_Generate_Index_Manifest); - Steps : constant array (Step_Names) of Step_Subprogram := - (Step_Prepare_Archive => Prepare_Archive'Access, - Step_Verify_Origin => Verify_Origin'Access, - Step_Verify_Github => Verify_Github'Access, - Step_Deploy_Sources => Deploy_Sources'Access, - Step_Check_Build => Check_Build'Access, - Step_Show_And_Confirm => Show_And_Confirm'Access, - Step_Generate_Index_Manifest => Generate_Index_Manifest'Access); + type Step_Array is array (Positive range <>) of Step_Names; + + Step_Calls : constant array (Step_Names) + of Step_Subprogram := + (Step_Check_User_Manifest => Check_User_Manifest'Access, + Step_Prepare_Archive => Prepare_Archive'Access, + Step_Verify_Origin => Verify_Origin'Access, + Step_Verify_Github => Verify_Github'Access, + Step_Deploy_Sources => Deploy_Sources'Access, + Step_Check_Build => Check_Build'Access, + Step_Show_And_Confirm => Show_And_Confirm'Access, + Step_Generate_Index_Manifest => Generate_Index_Manifest'Access); function Step_Description (Step : Step_Names) return String is (case Step is + when Step_Check_User_Manifest => "Verify user manifest", when Step_Prepare_Archive => "Prepare remote source archive", when Step_Verify_Origin => "Verify origin URL", when Step_Verify_Github => "Verify GitHub infrastructure", @@ -724,29 +824,26 @@ package body Alire.Publish is when Step_Show_And_Confirm => "User review", when Step_Generate_Index_Manifest => "Generate index manifest"); - -------------- - -- Start_At -- - -------------- - - procedure Start_At (Step : Step_Names; - Context : in out Data; - Up_To : Step_Names := Step_Names'Last) + --------------- + -- Run_Steps -- + --------------- + -- Gives feedback on the current step and dispatchs to its actual code + procedure Run_Steps (Context : in out Data; + Steps : Step_Array) is -- Manage publishing steps up to exhaustion or error begin - for Current in Step .. Up_To loop + for Current in Steps'Range loop Ada.Text_IO.New_Line; Trace.Info ("Publishing assistant: step" - & TTY.Emph (Integer'Image (Step_Names'Pos (Current) - - Step_Names'Pos (Step) + 1)) + & TTY.Emph (Integer'Image (Current)) & " of" - & TTY.Emph (Integer'Image (Step_Names'Pos (Up_To) - - Step_Names'Pos (Step) + 1)) - & ": " & TTY.Emph (Step_Description (Current))); + & TTY.Emph (Integer'Image (Steps'Last) + & ": " & TTY.Emph (Step_Description (Steps (Current))))); - Steps (Current) (Context); + Step_Calls (Steps (Current)) (Context); end loop; - end Start_At; + end Run_Steps; ------------------- -- Directory_Tar -- @@ -754,23 +851,27 @@ package body Alire.Publish is procedure Directory_Tar (Path : Any_Path := "."; Revision : String := "HEAD"; - Options : All_Options := (others => <>)) + Options : All_Options := New_Options) is Context : Data := (Options => Options, Origin => <>, + Path => +Path, Revision => +Revision, - Root => - Roots.Optional.Search_Root (Path), Tmp_Deploy_Dir => <>); - Guard : Directories.Guard (Directories.Enter (Context.Root.Value.Path)) + Guard : Directories.Guard (Directories.Enter (Base_Path (Context))) with Unreferenced; begin - -- TODO: start with filling-in/checking the local manifest. For now, - -- start directly with the archive creation. - - Start_At (Step_Prepare_Archive, Context); + Run_Steps (Context, + (Step_Check_User_Manifest, + Step_Prepare_Archive, + Step_Verify_Origin, + Step_Verify_Github, + Step_Deploy_Sources, + Step_Check_Build, + Step_Show_And_Confirm, + Step_Generate_Index_Manifest)); end Directory_Tar; ---------------------- @@ -779,7 +880,7 @@ package body Alire.Publish is procedure Local_Repository (Path : Any_Path := "."; Revision : String := "HEAD"; - Options : All_Options := (others => <>)) + Options : All_Options := New_Options) is Root : constant Roots.Optional.Root := Roots.Optional.Search_Root (Path); Git : constant VCSs.Git.VCS := VCSs.Git.Handler; @@ -787,7 +888,13 @@ package body Alire.Publish is begin case Root.Status is when Outside => - Raise_Checked_Error ("No Alire workspace found at " & TTY.URL (Path)); + if Options.Nonstandard_Manifest then + Trace.Debug ("Using non-stardard manifest location: " + & Options.Manifest); + else + Raise_Checked_Error ("No Alire workspace found at " + & TTY.URL (Path)); + end if; when Broken => Raise_Checked_Error (Errors.Wrap @@ -796,48 +903,68 @@ package body Alire.Publish is when Valid => null; end case; - if not Git.Is_Repository (Root.Value.Path) then - Git_Error ("no git repository found", Root.Value.Path); - end if; + declare + Root_Path : constant Any_Path := + (if Options.Nonstandard_Manifest + then Path + else Root.Value.Path); + begin - -- Do not continue if the local repo is dirty + if not Git.Is_Repository (Root_Path) then + Git_Error ("no git repository found", Root_Path); + end if; - Check_Git_Clean (Root.Value.Path, For_Archiving => False); + -- Do not continue if the local repo is dirty - -- If given a revision, extract commit and verify it exists locally + Check_Git_Clean (Root_Path, For_Archiving => False); - declare - Commit : constant String := - Git.Revision_Commit (Root.Value.Path, - (if Revision /= "" - then Revision - else "HEAD")); - begin - if Commit /= "" then - Log_Success ("Revision exists in local repository (" - & TTY.Emph (Commit) & ")."); - else - Raise_Checked_Error ("Revision not found in local repository: " - & TTY.Emph (Revision)); + -- If not given a revision, check the local manifest contents + -- already. No matter what, it will be checked again on the + -- deployed sources step. + + if Revision = "" or Revision = "HEAD" then + declare + Tmp_Context : Data := (Options => Options, others => <>); + begin + Check_User_Manifest (Tmp_Context); + end; end if; + -- If given a revision, extract commit and verify it exists locally + declare - use Utils; - Raw_URL : constant String := Git.Fetch_URL (Root.Value.Path); - -- The one reported by the repo, in its public form - - Fetch_URL : constant String := - -- With an added ".git", if it hadn't one. Not usable in local fs. - Raw_URL - & (if Ends_With (To_Lower_Case (Raw_URL), ".git") - then "" - else ".git"); + Commit : constant String := + Git.Revision_Commit (Root_Path, + (if Revision /= "" + then Revision + else "HEAD")); begin - -- To allow this call to succeed with local tests, we check - -- here. For a regular repository we will already have an HTTP - -- transport. A GIT transport is not wanted, because that one - -- requires the owner keys. - case URI.Scheme (Fetch_URL) is + if Commit /= "" then + Log_Success ("Revision exists in local repository (" + & TTY.Emph (Commit) & ")."); + else + Raise_Checked_Error ("Revision not found in local repository: " + & TTY.Emph (Revision)); + end if; + + declare + use Utils; + Raw_URL : constant String := Git.Fetch_URL (Root_Path); + -- The one reported by the repo, in its public form + + Fetch_URL : constant String := + -- With an added ".git", if it hadn't one. Not usable in local + -- filesystem. + Raw_URL + & (if Ends_With (To_Lower_Case (Raw_URL), ".git") + then "" + else ".git"); + begin + -- To allow this call to succeed with local tests, we check + -- here. For a regular repository we will already have an HTTP + -- transport. A GIT transport is not wanted, because that one + -- requires the owner keys. + case URI.Scheme (Fetch_URL) is when URI.VCS_Schemes => Raise_Checked_Error ("The remote URL seems to require repository ownership: " @@ -856,7 +983,8 @@ package body Alire.Publish is Options => Options); when others => Raise_Checked_Error ("Unsupported scheme: " & Fetch_URL); - end case; + end case; + end; end; end; end Local_Repository; @@ -867,7 +995,7 @@ package body Alire.Publish is procedure Remote_Origin (URL : Alire.URL; Commit : String := ""; - Options : All_Options := (others => <>)) + Options : All_Options := New_Options) is begin -- Preliminary argument checks @@ -903,13 +1031,19 @@ package body Alire.Publish is else Origins.New_Source_Archive (URL)), - Revision => +Commit, + Path => <>, -- will remain unused - Root => <>, -- Invalid root, as we are working remotely + Revision => +Commit, Tmp_Deploy_Dir => <>); begin - Start_At (Step_Verify_Origin, Context); + Run_Steps (Context, + (Step_Verify_Origin, + Step_Verify_Github, + Step_Deploy_Sources, + Step_Check_Build, + Step_Show_And_Confirm, + Step_Generate_Index_Manifest)); end; exception when E : Checked_Error | Origins.Unknown_Source_Archive_Format_Error => diff --git a/src/alire/alire-publish.ads b/src/alire/alire-publish.ads index 679babac..88ba1050 100644 --- a/src/alire/alire-publish.ads +++ b/src/alire/alire-publish.ads @@ -1,15 +1,18 @@ with Alire.Origins; +with Alire.Roots; with Alire.URI; package Alire.Publish is - type All_Options is record - Skip_Build : Boolean := False; - end record; + type All_Options is private; + + function New_Options (Skip_Build : Boolean := False; + Manifest : String := Roots.Crate_File_Name) + return All_Options; procedure Directory_Tar (Path : Any_Path := "."; Revision : String := "HEAD"; - Options : All_Options := (others => <>)); + Options : All_Options := New_Options); -- Publish the release at the given directory, by creating a source archive -- to be uploaded somewhere. Then proceed with Remote_Origin using the -- uploaded archive. If a git repo is at Path, `git archive` will be @@ -17,7 +20,7 @@ package Alire.Publish is procedure Local_Repository (Path : Any_Path := "."; Revision : String := "HEAD"; - Options : All_Options := (others => <>)) with + Options : All_Options := New_Options) with Pre => URI.Scheme (Path) in URI.File_Schemes; -- Check that given Path is an up-to-date git repo. If so, proceed with -- remote repo verification. If no revision given use the HEAD commit, @@ -25,7 +28,7 @@ package Alire.Publish is procedure Remote_Origin (URL : Alire.URL; Commit : String := ""; - Options : All_Options := (others => <>)); + Options : All_Options := New_Options); -- Requires a remote URL to a source file or a git repository. Commit is -- mandatory in the latter case. Produces a file `crate-version.toml` in -- the current directory or raises Checked_Error with the appropriate error @@ -34,4 +37,17 @@ package Alire.Publish is procedure Print_Trusted_Sites; -- Print our list of allowed sites to host git releases +private + + type All_Options is tagged record + Manifest_File : UString; + Skip_Build : Boolean := False; + end record; + + function Manifest (Options : All_Options) return Any_Path + is (+Options.Manifest_File); + + function Nonstandard_Manifest (Options : All_Options) return Boolean + is (Options.Manifest /= Roots.Crate_File_Name); + end Alire.Publish; diff --git a/src/alr/alr-commands-publish.adb b/src/alr/alr-commands-publish.adb index 6fbab132..e41c8b48 100644 --- a/src/alr/alr-commands-publish.adb +++ b/src/alr/alr-commands-publish.adb @@ -1,5 +1,6 @@ with Alire.Origins; with Alire.Publish; +with Alire.Roots; with Alire.URI; package body Alr.Commands.Publish is @@ -17,10 +18,17 @@ package body Alr.Commands.Publish is is (if Num_Arguments >= 2 then Argument (2) else ""); Options : constant Alire.Publish.All_Options := - (Skip_Build => Cmd.Skip_Build); + Alire.Publish.New_Options + (Manifest => + (if Cmd.Manifest.all /= "" + then Cmd.Manifest.all + else Alire.Roots.Crate_File_Name), + Skip_Build => Cmd.Skip_Build); begin - if Alire.Utils.Count_True ((Cmd.Tar, Cmd.Print_Trusted)) > 1 then + if Alire.Utils.Count_True ((Cmd.Tar, Cmd.Print_Trusted)) > 1 or else + (Cmd.Manifest.all /= "" and then Cmd.Print_Trusted) + then Reportaise_Wrong_Arguments ("Given switches cannot be simultaneously set"); end if; @@ -36,7 +44,6 @@ package body Alr.Commands.Publish is & " and optional revision are expected"); end if; - Requires_Valid_Session; Alire.Publish.Directory_Tar (Path => (if Num_Arguments >= 1 then Argument (1) else "."), Revision => (if Num_Arguments >= 2 then Argument (2) else "HEAD"), @@ -95,6 +102,12 @@ package body Alr.Commands.Publish is is use GNAT.Command_Line; begin + Define_Switch + (Config, + Cmd.Manifest'Access, + "", "--manifest=", + "Selects a manifest file other than ./alire.toml"); + Define_Switch (Config, Cmd.Tar'Access, diff --git a/src/alr/alr-commands-publish.ads b/src/alr/alr-commands-publish.ads index b927297d..d01b67ec 100644 --- a/src/alr/alr-commands-publish.ads +++ b/src/alr/alr-commands-publish.ads @@ -1,3 +1,5 @@ +private with GNAT.Strings; + package Alr.Commands.Publish is -- Publish lends a helping hand to automate submission of crates/releases. @@ -27,6 +29,8 @@ package Alr.Commands.Publish is .New_Line .Append ("Use --tar to create a source archive ready to be uploaded.") .New_Line + .Append ("Use --manifest to use metadata in a non-default file.") + .New_Line .Append ("See the above link for help with other scenarios.")); overriding @@ -40,11 +44,14 @@ package Alr.Commands.Publish is overriding function Usage_Custom_Parameters (Cmd : Command) return String - is ("[--skip-build] [--tar] [ [commit]]]"); + is ("[--skip-build] [--tar] [--manifest ] [ [commit]]]"); private type Command is new Commands.Command with record + Manifest : aliased GNAT.Strings.String_Access; + -- A manifest to use instead of the default one. + Print_Trusted : aliased Boolean := False; Skip_Build : aliased Boolean := False; diff --git a/testsuite/fix-versions.sh b/testsuite/fix-versions.sh index 9f462c48..ede72b7e 100755 --- a/testsuite/fix-versions.sh +++ b/testsuite/fix-versions.sh @@ -1,6 +1,6 @@ #!/bin/bash -oldversion=0.5 +oldversion=0.4 newversion=1.0 find . -type f -name index.toml -exec sed -i "s/$oldversion/$newversion/" {} \; diff --git a/testsuite/tests/publish/local-repo-nonstd/test.py b/testsuite/tests/publish/local-repo-nonstd/test.py new file mode 100644 index 00000000..06e0a30d --- /dev/null +++ b/testsuite/tests/publish/local-repo-nonstd/test.py @@ -0,0 +1,52 @@ +""" +Test proper publishing using a local repo as reference with custom manifest +""" + +from drivers.alr import init_local_crate, run_alr +from drivers.asserts import assert_match +from drivers.helpers import init_git_repo +from glob import glob +from shutil import rmtree +from subprocess import run + +import os + + +def verify_manifest(): + target = os.path.join("alire", "releases", "xxx-0.0.0.toml") + assert os.path.isfile(target), \ + "Index manifest not found at expected location" + # Clean up for next test + rmtree(os.path.join("alire", "releases")) + + +# Prepare our "remote" repo, changing the manifest name to "xxx.toml" +init_local_crate("xxx") +os.rename("alire.toml", "xxx.toml") +os.chdir("..") +head_commit = init_git_repo("xxx") + +# Clone to a "local" repo and set minimal config +assert run(["git", "clone", "xxx", "xxx_local"]).returncode == 0 +os.chdir("xxx_local") +assert run(["git", "config", "user.email", "alr@testing.com"]).returncode == 0 +assert run(["git", "config", "user.name", "Alire Testsuite"]).returncode == 0 + +# Tests with different default arguments that must all succeed +run_alr("--force", "publish", "--manifest", "xxx.toml") +verify_manifest() + +run_alr("--force", "publish", ".", "--manifest", "xxx.toml") +verify_manifest() + +run_alr("--force", "publish", ".", "master", "--manifest", "xxx.toml") +verify_manifest() + +run_alr("--force", "publish", ".", "HEAD", "--manifest", "xxx.toml") +verify_manifest() + +# Test that not setting the custom manifest results in failure +p = run_alr("--force", "publish", complain_on_error=False) +assert_match(".*No Alire workspace found.*", p.out) + +print('SUCCESS') diff --git a/testsuite/tests/publish/local-repo-nonstd/test.yaml b/testsuite/tests/publish/local-repo-nonstd/test.yaml new file mode 100644 index 00000000..8929d590 --- /dev/null +++ b/testsuite/tests/publish/local-repo-nonstd/test.yaml @@ -0,0 +1,4 @@ +driver: python-script +indexes: + basic_index: + in_fixtures: true diff --git a/testsuite/tests/publish/remote-origin-nonstd/test.py b/testsuite/tests/publish/remote-origin-nonstd/test.py new file mode 100644 index 00000000..79afac1d --- /dev/null +++ b/testsuite/tests/publish/remote-origin-nonstd/test.py @@ -0,0 +1,64 @@ +""" +Test proper publishing of a ready remote origin with custom manifest location +""" + +from drivers.alr import run_alr, index_version +from drivers.asserts import assert_match +from drivers.helpers import contents, content_of, init_git_repo, zip_dir +from shutil import copyfile, rmtree +from zipfile import ZipFile + +import os + + +def verify_manifest(): + target = os.path.join("alire", "releases", "xxx-0.0.0.toml") + assert os.path.isfile(target), \ + "Index manifest not found at expected location" + # Minimally check the expected contents are in the file + assert "[origin]" in content_of(target) + assert "url" in content_of(target) + +# create and add an index to check the manifest is loadable later on +os.makedirs(os.path.join("my_index", "xx", "xxx")) +with open(os.path.join("my_index", "index.toml"), "wt") as index_metadata: + index_metadata.write(f"version = '{index_version()}'\n") +run_alr("index", "--add", "my_index", "--name", "my_index") + +# Prepare a repo and a zipball to be used as "remote" targets for publishing +run_alr("init", "--bin", "xxx") +# Remove the alire cache +rmtree(os.path.join("xxx", "alire")) +# Rename the manifest location +os.rename(os.path.join("xxx", "alire.toml"), os.path.join("xxx", "xxx.toml")) + +# Create the zip +zip_dir("xxx", "xxx.zip") + +# Create repo with the sources +head_commit = init_git_repo("xxx") + +# A "remote" source archive. We force to allow the test to skip the remote +# check. Curl requires an absolute path to work. +target = os.path.join(os.getcwd(), "xxx.zip") +run_alr("publish", f"file:{target}", "--force", "--manifest", "xxx.toml") +# Should complete without error, check the generated file is in place +verify_manifest() + +# Clean up for the next test +rmtree("alire") + +# Same test, using directly the source repository +target = os.path.join(os.getcwd(), "xxx") +run_alr("publish", f"git+file:{target}", head_commit, + "--force", "--manifest", "xxx.toml") +verify_manifest() + +# Copy the new index manifest into the index +copyfile(os.path.join("alire", "releases", "xxx-0.0.0.toml"), + os.path.join("my_index", "xx", "xxx", "xxx-0.0.0.toml")) + +p = run_alr("search", "--crates") +assert "xxx" in p.out, "Crate not found in index contents" + +print('SUCCESS') diff --git a/testsuite/tests/publish/remote-origin-nonstd/test.yaml b/testsuite/tests/publish/remote-origin-nonstd/test.yaml new file mode 100644 index 00000000..32c747b3 --- /dev/null +++ b/testsuite/tests/publish/remote-origin-nonstd/test.yaml @@ -0,0 +1 @@ +driver: python-script diff --git a/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/alire.toml b/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/alire.toml new file mode 100644 index 00000000..5155534f --- /dev/null +++ b/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/alire.toml @@ -0,0 +1,10 @@ +description = "Shiny new project" +maintainers = [ +"your@email.here", +] +maintainers-logins = [ +"github-username", +] +name = "crate" +version = "0.0.0" + diff --git a/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/crate.gpr b/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/crate.gpr new file mode 100644 index 00000000..48ba9327 --- /dev/null +++ b/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/crate.gpr @@ -0,0 +1,22 @@ +project Crate is + + for Source_Dirs use ("src"); + for Object_Dir use "obj"; + for Exec_Dir use "bin"; + for Main use ("crate.adb"); + + package Builder is + for Switches ("ada") use ("-j0", "-g"); + end Builder; + + package Compiler is + for Switches ("ada") use + ("-gnatVa", "-gnatwa", "-g", "-O2", + "-gnata", "-gnato", "-fstack-check"); + end Compiler; + + package Binder is + for Switches ("ada") use ("-Es"); + end Binder; + +end Crate; diff --git a/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/src/crate.adb b/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/src/crate.adb new file mode 100644 index 00000000..53454b9f --- /dev/null +++ b/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/crates/crate/src/crate.adb @@ -0,0 +1,3 @@ +procedure Crate is +begin +end Crate; diff --git a/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/index/cr/crate/crate-1.0.0.toml b/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/index/cr/crate/crate-1.0.0.toml new file mode 100644 index 00000000..17796e85 --- /dev/null +++ b/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/index/cr/crate/crate-1.0.0.toml @@ -0,0 +1,13 @@ +# NOTE: this crate is not used in the text, but we need at least one crate in +# the index or the community index will get cloned due to empty in-memory +# catalog. + +description = "Sample crate" +name = "crate" +version = "1.0.0" +licenses = [] +maintainers = ["any@bo.dy"] +maintainers-logins = ["someone"] + +[origin] +url = "file:../../../crates/crate" diff --git a/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/index/index.toml b/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/index/index.toml new file mode 100644 index 00000000..346c93fc --- /dev/null +++ b/testsuite/tests/publish/tarball-plaindir-nonstd/my_index/index/index.toml @@ -0,0 +1 @@ +version = "1.0" diff --git a/testsuite/tests/publish/tarball-plaindir-nonstd/test.py b/testsuite/tests/publish/tarball-plaindir-nonstd/test.py new file mode 100644 index 00000000..28e45c11 --- /dev/null +++ b/testsuite/tests/publish/tarball-plaindir-nonstd/test.py @@ -0,0 +1,56 @@ +""" +Tests tarball publishing from non-vcs directory with custom manifest location +""" + +from drivers.alr import init_local_crate, run_alr +from glob import glob +from shutil import copyfile +from subprocess import run + +import drivers.helpers +import os + +# Prepare our "remote" repo +init_local_crate("xxx", enter=True) +# with custom manifest location +os.rename("alire.toml", "xxx.toml") + +canary = "canary.txt" + +# Create a canary file to double-check that it does not make into the tarball +with open(os.path.join("alire", canary), "wt") as file: + print(file, "...\n") + +# Publish it. We need to give input to alr, so we directly call it. We use the +# generated location as the "online" location, and this works because we are +# forcing. +p = run(["alr", "publish", "--skip-build", "--tar", "-q", "-f", "-n", + "--manifest", "xxx.toml"], + input=f"file:{os.getcwd()}/alire/archives/xxx-0.0.0.tbz2\n".encode()) +p.check_returncode() + +# Verify the generated file does not contain the alire folder +p = run(["tar", "tf", "alire/archives/xxx-0.0.0.tbz2"], + capture_output=True) +p.check_returncode() +assert "xxx-0.0.0/alire/" not in p.stdout.decode(), \ + "Unexpected contents in tarball: " + p.stdout.decode() + +# Verify the index manifest has been generated +assert os.path.isfile("./alire/releases/xxx-0.0.0.toml") + +os.chdir("..") + +# Add this manifest to our local index, and retrieve + build the crate +os.makedirs("my_index/index/xx/xxx") +copyfile("xxx/alire/releases/xxx-0.0.0.toml", + "my_index/index/xx/xxx/xxx-0.0.0.toml") + +run_alr("get", "--build", "xxx") # Should not err + +# Verify the canary didn't made through +os.chdir(glob("xxx_*")[0]) +assert not os.path.isfile(os.path.join("alire", canary)), \ + "Found canary file that should not be there" + +print('SUCCESS') diff --git a/testsuite/tests/publish/tarball-plaindir-nonstd/test.yaml b/testsuite/tests/publish/tarball-plaindir-nonstd/test.yaml new file mode 100644 index 00000000..0a859639 --- /dev/null +++ b/testsuite/tests/publish/tarball-plaindir-nonstd/test.yaml @@ -0,0 +1,4 @@ +driver: python-script +indexes: + my_index: + in_fixtures: false diff --git a/testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/alire.toml b/testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/alire.toml new file mode 100644 index 00000000..5155534f --- /dev/null +++ b/testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/alire.toml @@ -0,0 +1,10 @@ +description = "Shiny new project" +maintainers = [ +"your@email.here", +] +maintainers-logins = [ +"github-username", +] +name = "crate" +version = "0.0.0" + diff --git a/testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/crate.gpr b/testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/crate.gpr new file mode 100644 index 00000000..48ba9327 --- /dev/null +++ b/testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/crate.gpr @@ -0,0 +1,22 @@ +project Crate is + + for Source_Dirs use ("src"); + for Object_Dir use "obj"; + for Exec_Dir use "bin"; + for Main use ("crate.adb"); + + package Builder is + for Switches ("ada") use ("-j0", "-g"); + end Builder; + + package Compiler is + for Switches ("ada") use + ("-gnatVa", "-gnatwa", "-g", "-O2", + "-gnata", "-gnato", "-fstack-check"); + end Compiler; + + package Binder is + for Switches ("ada") use ("-Es"); + end Binder; + +end Crate; diff --git a/testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/src/crate.adb b/testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/src/crate.adb new file mode 100644 index 00000000..53454b9f --- /dev/null +++ b/testsuite/tests/publish/tarball-repo-nonstd/my_index/crates/crate/src/crate.adb @@ -0,0 +1,3 @@ +procedure Crate is +begin +end Crate; diff --git a/testsuite/tests/publish/tarball-repo-nonstd/my_index/index/cr/crate/crate-1.0.0.toml b/testsuite/tests/publish/tarball-repo-nonstd/my_index/index/cr/crate/crate-1.0.0.toml new file mode 100644 index 00000000..17796e85 --- /dev/null +++ b/testsuite/tests/publish/tarball-repo-nonstd/my_index/index/cr/crate/crate-1.0.0.toml @@ -0,0 +1,13 @@ +# NOTE: this crate is not used in the text, but we need at least one crate in +# the index or the community index will get cloned due to empty in-memory +# catalog. + +description = "Sample crate" +name = "crate" +version = "1.0.0" +licenses = [] +maintainers = ["any@bo.dy"] +maintainers-logins = ["someone"] + +[origin] +url = "file:../../../crates/crate" diff --git a/testsuite/tests/publish/tarball-repo-nonstd/my_index/index/index.toml b/testsuite/tests/publish/tarball-repo-nonstd/my_index/index/index.toml new file mode 100644 index 00000000..346c93fc --- /dev/null +++ b/testsuite/tests/publish/tarball-repo-nonstd/my_index/index/index.toml @@ -0,0 +1 @@ +version = "1.0" diff --git a/testsuite/tests/publish/tarball-repo-nonstd/test.py b/testsuite/tests/publish/tarball-repo-nonstd/test.py new file mode 100644 index 00000000..660fb6e2 --- /dev/null +++ b/testsuite/tests/publish/tarball-repo-nonstd/test.py @@ -0,0 +1,45 @@ +""" +Tests tarball publishing from a git repository with custom manifest location +""" + +from drivers.alr import init_local_crate, run_alr +from drivers.helpers import init_git_repo +from shutil import copyfile +from subprocess import run + +import os + +# Prepare our "remote" repo +init_local_crate("xxx", enter=True) +os.rename("alire.toml", "xxx.toml") + +# Initialize a repo right here +init_git_repo(".") + +# Clone it to simulate it's our local copy +os.chdir("..") +os.rename("xxx", "xxx_upstream") +run(["git", "clone", "xxx_upstream", "xxx"]).check_returncode() +os.chdir("xxx") + +# Publish it. We need to give input to alr, so we directly call it. We use the +# generated location as the "online" location, and this works because we are +# forcing. ".tgz" is used, as bzip2 is not supported by `git archive`. +p = run(["alr", "publish", "--skip-build", "--tar", "-q", "-f", "-n", + "--manifest", "xxx.toml"], + input=f"file:{os.getcwd()}/alire/archives/xxx-0.0.0.tgz\n".encode()) +p.check_returncode() + +# Verify the index manifest has been generated +assert os.path.isfile("./alire/releases/xxx-0.0.0.toml") + +os.chdir("..") + +# Add this manifest to our local index, and retrieve + build the crate +os.makedirs("my_index/index/xx/xxx") +copyfile("xxx/alire/releases/xxx-0.0.0.toml", + "my_index/index/xx/xxx/xxx-0.0.0.toml") + +run_alr("get", "--build", "xxx") # Should not err + +print('SUCCESS') diff --git a/testsuite/tests/publish/tarball-repo-nonstd/test.yaml b/testsuite/tests/publish/tarball-repo-nonstd/test.yaml new file mode 100644 index 00000000..0a859639 --- /dev/null +++ b/testsuite/tests/publish/tarball-repo-nonstd/test.yaml @@ -0,0 +1,4 @@ +driver: python-script +indexes: + my_index: + in_fixtures: false -- 2.39.5