I am writing a swift XCTest and I need to assess a sub process. I want to call the terminal, pass the path of an applescript to the terminal and execute it.
I've imported both UIKit and Foundation in the swift test file. When I go to write a constant like: let task = NSTask() the NSClass is not referenced in the NSObject, and as a result I get a message that it is a
Use of unresolved unidentifier NSTask
If I write let pipe = NSPipe() that is referenced and works. Why is NSTask inaccessible after importing UIkit and Foundation?
in swift 3.0 Apple changed NSTask API
To execute a cmd now is:
// Create a process (was NSTask on swift pre 3.0)
let task = Process()
// Set the task parameters
task.launchPath = "/bin/ls"
task.arguments = ["-laF#" , filePath]
// Create a Pipe and make the task
// put all the output there
let pipe = Pipe()
task.standardOutput = pipe
// Launch the task
task.launch()
// Get the data
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: String.Encoding.utf8)
print(output!)
Related
I want to write a simple app that puts the result of the command
/usr/bin/strings myfile
into a label in the normal MacOS interface. I am receiving this error
xcrun: error: cannot be used within an App Sandbox.
I tried to use the info here:
https://forums.developer.apple.com/thread/73554
and here:
ANY possible way to run the clang compiler from a Sandboxed app?
The actual piece of code invoking the instruction is:
let path = "/usr/bin/strings"
let arguments = ["/path/to/my/file"]
let task = Process()
task.arguments = arguments
task.executableURL = URL(fileURLWithPath: path)
let outputPipe = Pipe()
let errorPipe = Pipe()
task.standardOutput = outputPipe
task.standardError = errorPipe
do {
try task.run()
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
let output = String(decoding: outputData, as: UTF8.self)
let error = String(decoding: errorData, as: UTF8.self)
testo.stringValue="OUTPUT: \(output)\nERROR: \(error)"
} catch {
lbl.stringValue="Error somewhere"
}
Anyone does know how to solve this?
The problem is not the command (/usr/bin/strings) but the access to the filesystem. In fact, replacing the first two lines with:
let path = "/sbin/ping"
let arguments = ["-c", "1", "www.google.com"]
for instance, and allowing for outbound connections, would work fine. Hence, it is important that the application is allowed to access the path of the file to be processed, by means of the Sandbox.
I am developing osX app,
I need to open another App from MyApp
func openAnotherProcess(command:[String])
{
let task = Process()
task.launchPath = /PATH FOR WHICH WANT TO OPEN/
task.arguments = command
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.launch()
}
The above line successful open Application and window. this application has many window. But I want windowId of that window which has been open from MyApp.
I am able to get all running window but not able to distinguish the pericular WindowId
I have a sub-app in my main Swift app. I made it so it's copied automatically in the Resources folder of the main app when building it. That way, I want to be able to launch an instance of the sub-app from the main app.
The thing is, I'm having an error that is hard to debug/find answers about.
Here is my code :
let args = ["--args", "-admin_url", site.url, "-login", site.login, "-pass", site.password]
let helperPath = (NSBundle.mainBundle().pathForResource("App Helper", ofType: "app"))!
let task = NSTask.init()
task.launchPath = helperPath
task.arguments = args
task.launch()
And the error :
[56490:7218926] Couldn't posix_spawn: error 13
I have no idea where to look, what to search for. I don't know what I'm doing wrong.
I'm wondering if the issue is related to the sub-app itself. That sub-app is empty for now. I set Application is Agent to YES. And in MainMenu.xib, I set the Visible at launch option to no.
That sub-app needs to do some work in the background and doesn't need any UI at all.
Thanks !
Don't use NSTask for this, use NSWorkspace:
let helperAppURL = NSBundle.mainBundle().URLForResource("App Helper",
withExtension:"app")!
_ = try? NSWorkspace.sharedWorkspace().openURL(helperAppURL,
options:[.Default],
configuration:[NSWorkspaceLaunchConfigurationArguments :
["--args", "-admin_url", site.url, "-login",
site.login, "-pass", site.password]])
In the above code, for brevity, I ignored the result of the openURL() command, but in reality it can return an instance of NSRunningApplication which represents the task.
To keep track of the instances of your helper app you launch, you could keep references to this NSRunningApplication in an appropriate kind of collection class, and when the time comes, call its terminate() method.
the launch() function is deprecated, using run()
func shell(_ command: String) -> String {
let task = Process()
task.launchPath = "/usr/bin/"
task.arguments = ["-c", command]
let pipe = Pipe()
task.standardOutput = pipe
if #available(macOS 10.13, *) {
try? task.run()
} else {
task.launch()
}
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String
return output
}
or using swift-commands
import Commands
Commands.Bash.run("say hello")
I'm writing simple swift command line tool application that automates some of my iOS Dev work. Everything is working except one thing - calling xcodebuild script.
My method looks like this:
func runTest(deviceName: String, os: String) {
killAllSimulators()
let sdk = "iphonesimulator"
let destination = "platform=iOS Simulator,name=" + deviceName + ",OS=" + os
let arguments = ["-workspace", workspace, "-scheme", scheme, "-sdk", sdk, "-destination", destination, "test"]
executor.executeCommand("xcodebuild", arguments: arguments)
}
deviceName is equal to "iPhone 4s", os is equal to "9.0", workspace and scheme variables are properly set.
My execute command has simple implementation:
func executeCommand(command: String, arguments: [String]) -> NSString? {
_ = NSProcessInfo.processInfo().processIdentifier
let pipe = NSPipe()
let fileHandle = pipe.fileHandleForReading
let task = NSTask()
task.launchPath = "/usr/bin/" + command
task.arguments = arguments
task.standardOutput = pipe
task.launch()
let data = fileHandle.readDataToEndOfFile()
fileHandle.closeFile()
return NSString(data: data, encoding: NSUTF8StringEncoding)
}
i got error that test failed because cdtool cannot compile. Thats very weird because exactly the same script called from terminal works..
Any ideas?
I have code which invokes shell. Shell does some testing of the arguments and if they pass, it runs.
Right now, I post any errors to a log file but would like to return them to my swift program ...
let bundle = NSBundle.mainBundle()
let cmd = bundle.pathForResource("model", ofType: "sh")
let task = NSTask()
task.launchPath = cmd
task.arguments = [ "\(arg1.stringValue)", "\(arg2.stringValue)" ]
task.launch()
This works but how do I get the output of the shell short of reading the log file created in the shell.
Ran into this. Hope it helps.
http://practicalswift.com/2014/06/25/how-to-execute-shell-commands-from-swift/
#!/usr/bin/env xcrun swift -i
import Foundation
let task = NSTask()
task.launchPath = "/bin/echo"
task.arguments = ["first-argument", "second-argument"]
let pipe = NSPipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: NSUTF8StringEncoding)
print(output)
assert(output == "first-argument second-argument\n")
A project posted at github may be useful also:
https://github.com/kareman/SwiftShell