1

I want to launch a terminal application (like "git") in my Swift application on macOS. My code looks like this:

    do {
      let process: Process = Process();
      process.launchPath = "git";
      process.arguments = [
        "..."
      ];
      process.launch();
    } catch {
      print("Cannot launch git: \(error)")
    }

On my box git is on PATH and launches without problems in a terminal by just running git. How can I accomplish that in my Swift application too?

Can Process be made to resolve the application path on its own or do I have to do that myself? And if I have to do it manually, how would I do it?

Update: The start application is a GUI application, which can run from Finder as well as being debugged from Xcode.

I can read the PATH like this:

var env = ProcessInfo.processInfo.environment
var path = env["PATH"]! as String

but that value doesn't contain the terminal's PATH values.

Mike Lischke
  • 48,925
  • 16
  • 119
  • 181
  • Is it a command line app or a GUI app? For the latter, have a look at https://stackoverflow.com/q/41535451/1187415 – Martin R Jan 11 '21 at 09:58
  • You are suggesting to read the PATH values, construct a file path for each and try to access each of them to see if the file exists? – Mike Lischke Jan 11 '21 at 09:59
  • GUI apps have a different environment than your Terminal session, that makes it a bit more difficult. For a command line app it should be sufficient to launch "/usr/bin/env" with "git" as an argument, see for example https://stackoverflow.com/a/26973384. – Martin R Jan 11 '21 at 10:01
  • Indeed that works for `git` (which is in `/usr/bin`), but for a custom path which is on PATH that doesn't work. – Mike Lischke Jan 11 '21 at 10:06
  • Please clarify first: Is this a GUI app (started from the Finder) or a command-line app which you run from the Terminal? – Martin R Jan 11 '21 at 10:08
  • Or do you run it from within Xcode? In that case the problem is that Xcode (as a GUI app) has a different environment. – Martin R Jan 11 '21 at 10:11
  • I updated my question with that detail. – Mike Lischke Jan 11 '21 at 10:16
  • Try launching `"/bin/bash"` with the arguments `[ "--login", "-c", "git ..."];` , compare https://stackoverflow.com/a/58828362/1187415 – Martin R Jan 11 '21 at 10:21
  • Unfortunately, none of the linked solutions work for me. I get errors like `path_helper operation is not permitted`. However, even with some errors I can get `git` to launch somehow, but not other terminal apps, which are not in `/usr/bin`. Maybe because my GUI app doesn't have the same env variables. So I will first try to get this solved. – Mike Lischke Jan 11 '21 at 10:44
  • Sandboxing is another possible problem. – Martin R Jan 11 '21 at 10:47
  • I got it to work. You were close by suggesting to launch an own shell (`/bin/bash`) for the process. If you like you can post an answer here to get the points. I'll change it to include the actual solution I used. – Mike Lischke Jan 11 '21 at 15:54
  • 1
    You are welcome to post your solution as an answer! – Martin R Jan 12 '21 at 06:00

1 Answers1

0

A comment from @MartinR brought me to the right idea. Don't run the terminal command directly, but from a new shell. This way it will do the PATH resolution for you:

    let shellProcess = new Process();
    shellProcess.launchPath = "/bin/bash";
    shellProcess.arguments = [
      "-l",
      "-c",
      // Important: this must all be one parameter to make it work.
      "mysqlsh --py -e 'print(\"Call from shell\")",
    ];
    shellProcess.launch();

This example uses the MySQL shell as example, which is in /usr/local/bin (unlike git, which is in /usr/bin). Git worked already in the beginning, while mysqlsh did not. From the comment you can also see that it is important to make the mysqlsh call a complete and single parameter entry. If you split that then /bin/bash -c will only execute mysqlsh and not pass on the given shell parameters.

Mike Lischke
  • 48,925
  • 16
  • 119
  • 181