Skip to content

Commit

Permalink
Implement Homebrew as the system deployer for macOS. (#1185)
Browse files Browse the repository at this point in the history
* Implement Homebrew as the system deployer for macOS.

  * src/alire/alire-origins-deployers-system-homebrew.adb: new.
  * src/alire/alire-origins-deployers-system-homebrew.ads: new.
  * src/alire/alire-origins-deployers-system.adb (Platform_Deployer):
      When the platform distro manager is Homebrew, return Homebrew.Deployer.
  * src/alire/alire-platforms.ads (Distributions): include macOS.
    (Package_Managers): add Homebrew.
    (Distro_Manager): for macOS, use Homebrew.
  * src/alire/alire-utils-tools.adb (System_Package_For_Tool): treat MacOS
      like other distributions.
  * src/alire/os_macos/alire-platforms-current__macos.adb
    (Detected_Distribution): return Platforms.MacOS.
  * testsuite/drivers/helpers.py (on_macos()): new.
    (distribution()): return 'MACOS' if on_macos() is True.

; Squashed commit of the following:

; commit 0110299ceb66f58cd4793fd78a69fc5b100b4ccf
; Author: Simon Wright <[email protected]>
; Date:   Fri Sep 9 17:45:04 2022 +0100

;     Restore test to correct sense.

; commit d396b6b54a73bbbfd59071539bf6268bccce3cf0
; Author: Simon Wright <[email protected]>
; Date:   Fri Sep 9 17:34:54 2022 +0100

;     Replace assertions in Homebrew deployer with exceptions

; commit d7603110b9543bdaac9516fa844599e87fac70aa
; Author: Simon Wright <[email protected]>
; Date:   Mon Sep 5 14:14:03 2022 +0100

;     Recognise macOS as a distribution.

;       * testsuite/drivers/helpers.py (on_macos()): new.
;         (distribution()): check on_macos(). Return 'MACOS' if true.

; commit 8703acfeb8fdf336d862cefc16706eac5d3f0758
; Author: Simon Wright <[email protected]>
; Date:   Sun Sep 4 17:33:13 2022 +0100

;     Use 'brew info' to get available, installed versions.

; commit 8b22b904e19d64fecb89233e6527c2faf655d982
; Author: Simon Wright <[email protected]>
; Date:   Wed Aug 31 15:54:51 2022 +0100

;     Continuing.

; commit a9821ed9a605e30b5699a49df6fffd11224ab931
; Author: Simon Wright <[email protected]>
; Date:   Mon Aug 22 17:09:48 2022 +0100

;     First changes for macOS Homebrew.

* Implement Homebrew for MacOS: response to comments on PR#1185

  * .github/workflows/ci-macos.yml (Run test script): renamed to
      "Run test script (without Homebrew)".
    (Run test script (with Homebrew)): added 'eval $(brew shellenv)' before
      running the test script, so that HOMEBREW_PREFIX gets defined.
  * src/alire/alire-origins-deployers-system-homebrew.adb
    (Homebrew_Prefix, Homebrew_Present): removed.
    (Get_Info): named the declare block. Removed commented-out exception
      handler.
    (Already_Installed): use Get_Info's returned Installed_Version's length
      to determine the result.
    (Detect): Get_Version_From_String uses Semantic_Versioning.Parse.
        Don't check for Homebrew_Present, it has to be or we wouldn't be
        called.
  * src/alire/alire-platforms.ads (Distributions): rename MacOS to Homebrew.
    (Distro_Manager): likewise.
  * src/alire/alire-utils-tools.adb (System_Package_For_Tool): MacOS (in
      'case Distribution)' changed to Homebrew.
  * src/alire/os_macos/alire-platforms-current__macos.adb
    (Homebrew_Prefix): new, gets the environment variable "HOMEBREW_PREFIX".
    (Homebrew_Present): new, true if the environment variable is present.
    (Detected_Distribution): checks Homebrew_Present, returns Homebrew
      or Distro_Unknown accordingly.
    (Distribution_Root): returns Homebrew_Prefix if present, otherwise "/".
  * testsuite/drivers/helpers.py (distribution()): if on macOS, return
      HOMEBREW if HOMEBREW_PREFIX is found, DISTRO_UNKNOWN otherwise.

* Remove improper pragma in response to comment on #1185

  * src/alire/alire-origins-deployers-system-homebrew.adb: removed
      the innefective pragma Warnings (Off).

* Merging with openSUSE changes in #1173.

  * src/alire/alire-origins-deployers-system.adb: added Homebrew option.
  * src/alire/alire-platforms.ads: likewise.
  * src/alire/alire-utils-tools.adb: likewise.

Co-authored-by: John Serock <[email protected]>
Co-authored-by: GHA <[email protected]>
  • Loading branch information
3 people authored Sep 23, 2022
1 parent 256a97d commit 9842f32
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 8 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/ci-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,22 @@ jobs:
with:
python-version: '3.x'

- name: Run test script
- name: Run test script (without Homebrew)
run: scripts/ci-github.sh
shell: bash
env:
BRANCH: ${{ github.base_ref }}
INDEX: ""

- name: Run test script (with Homebrew)
run: |
eval $(brew shellenv)
scripts/ci-github.sh
shell: bash
env:
BRANCH: ${{ github.base_ref }}
INDEX: ""

- name: Upload binaries
uses: actions/upload-artifact@v2
with:
Expand Down
217 changes: 217 additions & 0 deletions src/alire/alire-origins-deployers-system-homebrew.adb
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
with AAA.Strings; use AAA.Strings;

with Alire.OS_Lib.Subprocess;
with Alire.Errors;

with GNATCOLL.JSON;

package body Alire.Origins.Deployers.System.Homebrew is

-- Ada.Strings.Unbounded is use-visible via Alire.Origins.
use GNATCOLL.JSON;

package Subprocess renames Alire.OS_Lib.Subprocess;

procedure Get_Info (Package_Name : String;
Available_Version : out Unbounded_String;
Installed_Version : out Unbounded_String);
-- Queries the versions using 'brew info'.

procedure Get_Info (Package_Name : String;
Available_Version : out Unbounded_String;
Installed_Version : out Unbounded_String)
is

-- The format of the JSON returned by 'brew info --json=v1 {pkg}' is
-- [
-- {
-- "stuff": {},
-- "versions": {
-- "stable": "1.2.4_0",
-- "stuff": {}
-- },
-- "stuff": {},
-- "installed": [
-- {
-- "version": "1.2.3_1",
-- "stuff": {}
-- }
-- ],
-- "stuff": {}
-- }
-- ]

Info : AAA.Strings.Vector;
JSON_Issue : exception;
begin
if Subprocess.Unchecked_Spawn_And_Capture
("brew",
Empty_Vector & "info" & "--json=v1" & Package_Name,
Output => Info,
Err_To_Out => True) /= 0
then
-- failed.
Trace.Debug ("brew failed to find " & Package_Name);
Available_Version := Null_Unbounded_String;
Installed_Version := Null_Unbounded_String;
return;
end if;

Homebrew_Found_Required_Package :
declare
Data : constant JSON_Value := Read (AAA.Strings.Flatten (Info));

procedure Get_Available_Version
(From : JSON_Value;
Version : out Ada.Strings.Unbounded.Unbounded_String)
with Pre => Kind (From) = JSON_Object_Type;
procedure Get_Installed_Version
(From : JSON_Array;
Version : out Ada.Strings.Unbounded.Unbounded_String);
procedure Info_Callback (Name : UTF8_String; Value : JSON_Value);
-- Called for the elements of the JSON data to find the
-- relevant sections and use Get_Available_Version,
-- Get_Installed_Version to extract the actual versions (if
-- any).

procedure Get_Available_Version
(From : JSON_Value;
Version : out Ada.Strings.Unbounded.Unbounded_String)
is
begin
Version := Ada.Strings.Unbounded.To_Unbounded_String
(String'(Get (From, "stable")));
end Get_Available_Version;

procedure Get_Installed_Version
(From : GNATCOLL.JSON.JSON_Array;
Version : out Ada.Strings.Unbounded.Unbounded_String)
is
Result : Ada.Strings.Unbounded.Unbounded_String;
procedure Installed_Callback (Name : UTF8_String;
Value : JSON_Value);
procedure Installed_Callback (Name : UTF8_String;
Value : JSON_Value)
is
begin
if Name = "version" then
Result := Ada.Strings.Unbounded.To_Unbounded_String
(String'(Get (Value)));
end if;
end Installed_Callback;
begin
if Length (From) /= 0 then
Map_JSON_Object (Get (From, 1), Installed_Callback'Access);
end if;
Version := Result;
end Get_Installed_Version;

procedure Info_Callback (Name : UTF8_String; Value : JSON_Value) is
function "+"
(L : Ada.Strings.Unbounded.Unbounded_String) return String
renames Ada.Strings.Unbounded.To_String;
begin
if Name = "versions" then
if Kind (Value) /= JSON_Object_Type then
raise JSON_Issue with "JSON 'versions' not JSON_Object";
end if;
Get_Available_Version (Value, Available_Version);
Trace.Debug ("available: " & (+Available_Version));
elsif Name = "installed" then
if Kind (Value) /= JSON_Array_Type then
raise JSON_Issue with "JSON 'installed' not JSON_Array";
end if;
Get_Installed_Version (JSON_Array'(Get (Value)),
Installed_Version);
Trace.Debug ("installed: " & (+Installed_Version));
end if;
end Info_Callback;

Arr : JSON_Array;
begin
if Kind (Data) /= JSON_Array_Type then
raise JSON_Issue with "JSON info not JSON_Array";
end if;
Arr := Get (Data);
if Length (Arr) /= 1 then
raise JSON_Issue with "JSON info length /= 1";
end if;
if Kind (Get (Arr, 1)) /= JSON_Object_Type then
raise JSON_Issue with "JSON info (1) not JSON_Object";
end if;
Map_JSON_Object (Get (Arr, 1), Info_Callback'Access);
end Homebrew_Found_Required_Package;

end Get_Info;

-----------------------
-- Already_Installed --
-----------------------

overriding function Already_Installed (This : Deployer) return Boolean
is
Installed_Version : Unbounded_String;
Available_Version : Unbounded_String;
begin
Trace.Debug ("already_installed? " & This.Base.Package_Name);

Get_Info (Package_Name => This.Base.Package_Name,
Available_Version => Available_Version,
Installed_Version => Installed_Version);
return Length (Installed_Version) > 0;
end Already_Installed;

------------
-- Detect --
------------

overriding
function Detect (This : Deployer) return Version_Outcomes.Outcome
is

function Get_Version_From_String (Candidate : String)
return Version_Outcomes.Outcome
is (Version_Outcomes.New_Result (Semantic_Versioning.Parse
(Candidate,
Relaxed => True)));

Installed_Version : Unbounded_String;
Available_Version : Unbounded_String;
begin
Trace.Debug ("detect? " & This.Base.Package_Name);

Get_Info (Package_Name => This.Base.Package_Name,
Available_Version => Available_Version,
Installed_Version => Installed_Version);

if Length (Installed_Version) > 0 then
return Get_Version_From_String (To_String (Installed_Version));
elsif Length (Available_Version) > 0 then
return Get_Version_From_String (To_String (Available_Version));
else
return Version_Outcomes.Outcome_Failure
("no candidate version found",
Report => False);
end if;

end Detect;

-------------
-- Install --
-------------

overriding
function Install (This : Deployer) return Outcome is
begin
Trace.Debug ("hoping to install: " & This.Base.Image);
Subprocess.Checked_Spawn
("brew",
Empty_Vector & "install" & This.Base.Package_Name);

return Outcome_Success;
exception
when E : others =>
return Alire.Errors.Get (E);
end Install;

end Alire.Origins.Deployers.System.Homebrew;
15 changes: 15 additions & 0 deletions src/alire/alire-origins-deployers-system-homebrew.ads
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package Alire.Origins.Deployers.System.Homebrew is

type Deployer is new Deployers.System.Deployer with null record;

overriding
function Already_Installed (This : Deployer) return Boolean;

overriding
function Detect (This : Deployer)
return Version_Outcomes.Outcome;

overriding
function Install (This : Deployer) return Outcome;

end Alire.Origins.Deployers.System.Homebrew;
6 changes: 5 additions & 1 deletion src/alire/alire-origins-deployers-system.adb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
with Alire.Origins.Deployers.System.Apt;
with Alire.Origins.Deployers.System.Homebrew;
with Alire.Origins.Deployers.System.Pacman;
with Alire.Origins.Deployers.System.RPM_Wrappers;
with Alire.Origins.Deployers.System.Zypper;
Expand Down Expand Up @@ -104,7 +105,10 @@ package body Alire.Origins.Deployers.System is
others => <>),
when Platforms.Zypper =>
System.Zypper.Deployer'(Deployers.Deployer'(Base => From)
with others => <>));
with others => <>),
when Platforms.Homebrew =>
System.Homebrew.Deployer'(Deployers.Deployer'(Base => From)
with others => <>));
-- NOTE: add here other native package managers as they get
-- implemented.

Expand Down
3 changes: 3 additions & 0 deletions src/alire/alire-platforms.ads
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ package Alire.Platforms with Preelaborate is
Centos,
Fedora,
Suse,
Homebrew,
Distro_Unknown);

subtype Known_Distributions is
Expand All @@ -56,6 +57,7 @@ package Alire.Platforms with Preelaborate is
Yum,
Dnf,
Zypper,
Homebrew,
Packager_Unknown);

Distro_Manager : constant array (Distributions) of Package_Managers :=
Expand All @@ -64,6 +66,7 @@ package Alire.Platforms with Preelaborate is
Rhel => Yum,
Centos | Fedora => Dnf,
Suse => Zypper,
Homebrew => Homebrew,
Distro_Unknown => Packager_Unknown);

type Toolchains is (System,
Expand Down
9 changes: 5 additions & 4 deletions src/alire/alire-utils-tools.adb
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ package body Alire.Utils.Tools is
-- Cannot have package for an unknown distribution
return "";

when Msys2 | Debian | Ubuntu | Arch | Centos | Fedora | Rhel | Suse =>
when Msys2 | Debian | Ubuntu | Arch | Centos | Fedora | Rhel | Suse
| Homebrew =>
return (case Tool is
when Easy_Graph =>
(if Distribution = Centos or else
Distribution = Fedora or else
Distribution = Rhel or else
Distribution = Suse
Distribution = Fedora or else
Distribution = Rhel or else
Distribution = Suse
then "perl-Graph-Easy"
elsif Distribution /= Msys2 and Distribution /= Arch
then "libgraph-easy-perl"
Expand Down
13 changes: 11 additions & 2 deletions src/alire/os_macos/alire-platforms-current__macos.adb
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,29 @@ with Alire.OS_Lib;
package body Alire.Platforms.Current is

-- macOS implementation
-- Homebrew only at this time (2022-09-13)

Homebrew_Prefix : constant String
:= Alire.OS_Lib.Getenv ("HOMEBREW_PREFIX", "");
Homebrew_Present : constant Boolean := Homebrew_Prefix /= "";

------------------
-- Distribution --
------------------

function Detected_Distribution return Platforms.Distributions is
(Platforms.Distro_Unknown);
(if Homebrew_Present
then Homebrew
else Distro_Unknown);

-----------------------
-- Distribution_Root --
-----------------------

function Distribution_Root return Absolute_Path
is ("/");
is (if Homebrew_Present
then Homebrew_Prefix
else "/");

----------------------
-- Load_Environment --
Expand Down
10 changes: 10 additions & 0 deletions testsuite/drivers/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ def check_line_in(filename, line):
repr(line), filename, content_of(filename))


def on_macos():
return platform.system() == "Darwin"


def on_windows():
return platform.system() == "Windows"

Expand All @@ -89,6 +93,12 @@ def distribution():

return 'DISTRO_UNKNOWN'

elif on_macos():
if os.environ.get('HOMEBREW_PREFIX'):
return 'HOMEBREW'
else:
return 'DISTRO_UNKNOWN'

elif on_windows():
return 'MSYS2'
else:
Expand Down

0 comments on commit 9842f32

Please sign in to comment.