Recent

Author Topic: [Solved] Using TProcess to execute and interact with pacman package manager  (Read 568 times)

SuperSathanas

  • New Member
  • *
  • Posts: 16
I think that I have a couple different problems/things I lack understanding in that are causing me some issues here, so forgive me if I'm not being very clear or leaving out relevant information. I don't know what I don't know at this point. I'll be happy to provide more information if needed.

Some background on what I'm doing: I have a bash script (appropriately named backupdate) that queries pacman for updateable packages, and if there are any, updates and ranks pacman's mirrors, creates a system snapshot using timeshift, performs pacman updates, then executes a separate program I wrote in FPC that gets rid of excessive timeshift snapshots, before optionally rebooting. This works fine, but I wanted to write the entire thing in FPC.

I'm using TProcess to query pacman, run reflector to update and rank mirrors and call my other program, capture and act on their outputs, and that's all working fine. Where I'm running into an issue is with actually executing pacman and doing the updates. I need to call
Code: Pascal  [Select][+][-]
  1. pacman -Syu
and then automatically have it respond to prompts and continue to capture the output to display to the user (me).

I've managed to have it automatically respond to the prompt asking the user to proceed (:: Proceed with installation? [Y/n]), by scanning each line of the process's output, looking for a "y/n" or a variant thereof and writing a "y" to the input stream. However, after responding to the prompt and receiving the next line of output from pacman, ":: Retrieving packages...", nothing seems to happen. The TProcess instance keeps running, but I no longer receive any output from pacman, pacman seems to not move on (if I interrupt the process, no updates have been installed including no partial updates), and the whole program is just stuck waiting on that TProcess.

However, if I don't write to the input stream, and just manually enter "y" when prompted, everything works and pacman does it's thing.

Essentially what I'm trying to do is the equivalent of
Code: Pascal  [Select][+][-]
  1. yes | pacman -Syu
in the terminal, just "yessing" through prompts.

Currently, this is what the procedure that handles updates looks like. It's not optimal, but I'm not worried about cleaning it up and doing things more efficiently until I get my current problem solved.

Code: Pascal  [Select][+][-]
  1. procedure DoUpdates();
  2. var
  3. proc: TProcess;
  4. OList: TStringList;
  5. CheckString: String;
  6. I: Integer;
  7.   begin
  8.     OList := TStringList.Create();
  9.  
  10.     proc := TProcess.Create(nil);
  11.     proc.Options := proc.Options + [poUsePipes, poWaitOnExit];
  12.     proc.CommandLine := 'pacman -Syu';
  13.     proc.Execute();
  14.  
  15.     while proc.Running do begin
  16.       OList.LoadFromStream(proc.OutPut);
  17.  
  18.       if OList.Count > 0 then begin
  19.         for I = 0 to OList.Count - 1 do begin
  20.           WriteLn(OList[I]);
  21.           CheckString := LowerCase(OList[I]);
  22.  
  23.           if Pos('y/n', CheckString) <> 0 then begin
  24.             CheckString := 'y' + #10;
  25.             proc.Input.Write(CheckString[0], Length(CheckString));
  26.             proc.CloseInput();
  27.           end;
  28.  
  29.         end;
  30.       end;
  31.  
  32.     end;
  33.  
  34.     proc.Free();
  35.     OList.Free();
  36.  
  37.   end;
  38.  

Not super sophisticated, but we're not too concerned with speed at this point.

Any idea what it is about writing that "y" + #10 to the input stream is causing the whole thing to hang? It's weird to me that I'm able to respond to the prompt, get the next line of output from TProcess, but then it stalls, whereas if I do not handle the prompt programmatically, it all works.
« Last Edit: May 21, 2024, 02:43:18 am by SuperSathanas »

Roland57

  • Sr. Member
  • ****
  • Posts: 445
    • msegui.net
Hello!

I suggest you to take a look at this demo: https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/examples/process/

Unless I am wrong, it does what you are trying to do.
My projects are on Gitlab and on Codeberg.

SuperSathanas

  • New Member
  • *
  • Posts: 16
That example does show a better way of waiting for and receiving output than what I did (waiting until TProcess.NumBytesAvailable > 0 instead of me just trying to read the output into a string list and then checking the length of list). My sloppiness there may be causing the issue, so I'll try doing it the way shown in the example and see if it still hangs.

I see that they do not call TProcess.CloseInput(), whereas I currently am. I ended up adding that in to see if that would stop it from hanging, basically just throwing darts at the board when I was out of ideas, but I guess I'll go ahead and remove that as well and see how it goes with handling the output differently.

SuperSathanas

  • New Member
  • *
  • Posts: 16
Well, it turns out it was as simple as checking for TProcess.Output.NumBytesAvailable <> 0 instead of just trying to read the output into the string list each iteration. I guess maybe next time I won't be so sloppy, intending to fix things up later.
« Last Edit: May 21, 2024, 03:00:26 pm by SuperSathanas »

 

TinyPortal © 2005-2018