Redirect Process stdout to Apple System Log Facility in Swift - swift

I'm building a Swift app for macOS that launch a sub-process. This subprocess logs useful information to stdout, and I see it in the Xcode console.
What I would want to achieve now is to redirect the sub-process stdout to the Apple Log Facility so that we can access the data when the app is deployed.
Basically, this:
let task = Process()
task.launchPath = "subprocess"
task.standardOutput = // AppleSystemLogPipe
task.launch()
But I don't know how to refer to the Apple System Log Pipe. Any clues for this?
Best regards!

I finally managed to do this. Basically, we define a Pipe to catch the process output and, in an handler, call the OS function os_log with the data read:
let pipe = Pipe()
let outHandle = pipe.fileHandleForReading
outHandle.readabilityHandler = { pipe in
if let line = String(data: pipe.availableData, encoding: .utf8) {
// Define the placeholder as public, otherwise the Console obfuscate it
os_log("%{public}#", line)
}
}
let task = Process()
task.launchPath = "subprocess"
task.standardOutput = pipe // Redirect stdout to our pipe
task.launch()
In development, it is displayed in the Xcode console ; and when deployed it is redirected to the Apple Log System.

Related

Open an http tunnel through a shell script programmatically in swift

I am trying to open either an Ngrok or Localtunnel as part of my swift program by using shell scripts. The problem is as neither shell script has a return, my main thread hangs. I could put it in a side thread that's permanently open, but I need to extract the url that gets outputted. Any ideas?
For reference this is how I am executing shell commands in swift.
func shell(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.arguments = ["-c", command]
task.launchPath = "/bin/zsh"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}
followed by either
shell("ngrok http 3000")
or
shell("lt --port 9726")

Executing python from swift via bash: "can't open file...[Errno 1] Operation not permitted"

I am learning how to make apps for mac, and I am starting with an app to manage my many discord bots. Essentially, the goal is to have many switches to turn bots on and off, which requires executing the python files for the bots, written using discord.py. I read about a PythonKit module for swift, but when I tried to run a discord bot from the files using that, the build continuously failed, so I decided to use the bash shell to excecute the python. Here is my swift code for using bash shell commands:
func shell(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.arguments = ["-c", command]
task.launchPath = "/bin/zsh"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}func shell(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.arguments = ["-c", command]
task.launchPath = "/bin/zsh"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}
I then called shell("/usr/local/bin/python3.9 path/to/file.py"), and made it print the output to the console. This was the output:
/usr/local/bin/python3.9: can't open file 'path/to/file.py': [Errno 1] Operation not permitted. I am running this from both AppCode and Xcode, and made sure to give both of those apps full disk access, as well as giving terminal full disk access to be sure. In addition, I tried running /usr/local/bin/python3.9 path/to/file.pyin my terminal, and it works fine. What is happening here? Why can swift not open this file in the bash shell while I can? What do I do to fix it? Let me know if you need more info(if you think PythonKit is the answer, I'll send the build error info from that to debug that process)
Thanks!
Yonatan Vainer was right, turns out sandboxing was on in the entitlements file, so I had to set it to off, which fixed it.

How to run command with administrator privileges

I want to implement a simple mac app which will run some commands with administrator privileges.
What I've done is the code below
func execute(command: String) -> String {
var arguments:[String] = []
arguments.append("-c")
arguments.append(command)
let task = Process()
task.launchPath = "/bin/sh"
task.arguments = arguments
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.launch()
task.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
return String(data: data, encoding: .utf8)!
}
This is working for commands without sudo, when I'm putting sudo in the beginning of command I get this error /bin/sh: /usr/bin/sudo: Operation not permitted
I just want somehow to give the user's password or ask it native?
Any ideas?
I found the solution, keep the code as it is and the command should be in this format:
"osascript -e 'do shell script \"my command\" with administrator privileges'"
I tried to use it before but I had to put quotes and single quotes as above!
With that the native alert of apple is presenting.

Kill process in swift

I am trying to make a Mac application that will automatically close a code designated application running on the OS. I am trying to use killall (like in Terminal). Whenever I try to run the program, I get, "sysctl: unknown oid 'killall'".
Here's my code:
let task = Process()
task.launchPath = "/usr/sbin/sysctl"
///usr/sbin/sysctl
task.arguments = ["killall","iTunes"]
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.launch()
task.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
print(output)
Thanks in advance!
my 2 cents:
You succeed in killing "iTunes" only if You Xcode App will run with SandoBox DISABLED
All examples on stack overflow about Process are misleading as they call "ls" or "echo" that are always executed in system folders.
I'd suggest you first read the man page for sysctl -- it's used to get and set kernel state. Does that sound like something you want?
The path to killall is /usr/bin/killall, which you can find from Terminal:
> which killall
/usr/bin/killall
Here's the full Swift code:
let pipe = Pipe()
let task = Process()
task.launchPath = "/usr/bin/killall"
task.arguments = ["iTunes"]
task.standardOutput = pipe
task.standardError = pipe
task.launch()
task.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
if let output = String(data: data, encoding: .utf8) {
print(output)
}

Run pdflatex command in Swift with App Sandbox turned ON

I want to compile a latex file in swift, I am able to compile the file if the application has the App Sandbox OFF.
If I turn App Sandbox ON and try to compile I get the error: "launch path not accessible"
How can I run the pdflatex command to compile the latex file with the App Sandbox turned ON?
Below is the method the I use and it works with App Sandbox turned OFF.
let latexCmd = "/Users/user/Desktop/test/article.tex"
let logText:String = self.runTerminal(command: latexCmd)
func runTerminal(command: String)->String{
let pipe:Pipe = Pipe()
let task:Process = Process()
task.launchPath = "/Library/TeX/texbin/pdflatex"
task.arguments = ["-file-line-error", "-interaction=nonstopmode", "-synctex=1", command]
task.standardOutput = pipe
task.currentDirectoryPath = "/Users/user/Desktop/test"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
return output!
}