getada_1.0.1_e3e93ee6/src/commands.adb

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
--    Copyright (C) 2024 A.J. Ianozi <aj@ianozi.com>
--
--    This file is part of GetAda: the Unofficial Alire Installer
--
--    This program is free software: you can redistribute it and/or modify
--    it under the terms of the GNU General Public License as published by
--    the Free Software Foundation, either version 3 of the License, or
--    (at your option) any later version.
--
--    This program is distributed in the hope that it will be useful,
--    but WITHOUT ANY WARRANTY; without even the implied warranty of
--    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--    GNU General Public License for more details.
--
--    You should have received a copy of the GNU General Public License
--    along with this program.  If not, see <https://www.gnu.org/licenses/>.

with Ada.Characters.Handling; use Ada.Characters.Handling;
with Ada.Strings.Fixed;
with GNAT.Expect;             use GNAT.Expect;
with GNAT.OS_Lib;
with Platform; use Platform;
package body Commands is

   function Test_Command (Cmd : String) return Boolean
   is
      Test_Args : constant GNAT.OS_Lib.Argument_List (1 .. 1) :=
         (1 => new String'("--version"));
      Successfully_Executed : Boolean;
   begin
      GNAT.OS_Lib.Spawn
         (Program_Name => Cmd,
          Args         => Test_Args,
          Success      => Successfully_Executed);
      return Successfully_Executed;
   end Test_Command;

   function Is_Executable (Path : String) return Boolean is
      Test_Arg : constant GNAT.OS_Lib.Argument_List (1 .. 1) :=
         (1 => new String'(Path));
   begin
      declare
         Status   : aliased Integer := 0;
         Response : constant String :=
                     Get_Command_Output
                     (Command => "file",
                     Arguments => Test_Arg,
                     Input => "",
                     Status  => Status'Access);
      begin
         return Ada.Strings.Fixed.Index (Response, "executable") > 0;
      exception
         when others => return False;
      end;
   end Is_Executable;

   function Test_Commands return Command_Supported is
      Test_Args : constant GNAT.OS_Lib.Argument_List (1 .. 1) :=
         (1 => new String'("--version"));
   begin
      return Result : Command_Supported do
         --  TODO: A better way of doing this....
         for I in Possible_Commands'Range loop
            begin
               declare
                  Status   : aliased Integer := 0;
                  Response : constant String :=
                     Get_Command_Output
                     (Command => To_Lower (Possible_Commands'Image (I)),
                     Arguments => Test_Args,
                     Input => "",
                     Status  => Status'Access);
               begin
                  Result (I) := True;
               end;
            exception
               when GNAT.Expect.Invalid_Process =>
                  Result (I) := False;
            end;
         end loop;
      end return;
   end Test_Commands;

   function Test_Binary
       (Binary_To_Test : String; IO : C_IO; Ignore_IO : Boolean := False)
   return Boolean is
      type Checks is (Chmod, Macos_xattr);
      Tested : array (Checks'Range) of Boolean :=
      (Macos_xattr => (if OS = MacOS then False else True),
         others => False);
   begin
      Test_Alire :
      loop
         if not Ignore_IO then
            IO.Say_Line
            ("Testing binary by running """ & Binary_To_Test & " --version""");
         end if;
         if not Test_Command (Binary_To_Test) then
            if not Ignore_IO then
               IO.Say_Line
               ("Unable to run binary... Attempting to troubleshoot.");
            end if;
            if not Tested (Chmod) then
               declare
                  Chmod_Success : Boolean;
                  Chmod_Args : constant GNAT.OS_Lib.Argument_List
                  (1 .. 2) :=
                  (1 => new String'("+x"),
                     2 => new String'(Binary_To_Test));
               begin
                  --  TODO: Handle if they don't have chmod
                  --    or if it's not stored at /bin/chmod
                  if not Ignore_IO then
                     IO.Say_Line
                     ("Attempting ""/bin/chmod +x " & Binary_To_Test & """");
                  end if;
                  GNAT.OS_Lib.Spawn
                  (Program_Name => "/bin/chmod", Args => Chmod_Args,
                     Success      => Chmod_Success);
                  Tested (Chmod) := True;
               end;
            elsif not Tested (Macos_xattr) then
               declare
                  xattr_Success : Boolean;
                  xattr_Args : constant GNAT.OS_Lib.Argument_List
                  (1 .. 3) :=
                  (1 => new String'("-d"),
                     2 => new String'("com.apple.quarantine"),
                     3 => new String'(Binary_To_Test));
               begin
                  if not Ignore_IO then
                     IO.Say_Line
                     ("Attempting ""/usr/bin/xattr -d " &
                        "com.apple.quarantine " & Binary_To_Test & """");
                  end if;
                  GNAT.OS_Lib.Spawn
                  (Program_Name => "/usr/bin/xattr", Args => xattr_Args,
                     Success      => xattr_Success);
               end;
               Tested (Macos_xattr) := True;
            else -- not chmod_tried
               return False;
            end if;
         else
            if not Ignore_IO then
               IO.Say_Line ("Sucessfully able to run binary.");
            end if;
            exit Test_Alire;
         end if;
      end loop Test_Alire;
      return True;
   end Test_Binary;

end Commands;