To run xcpretty command in xcodebuild, i use the below code:
import Foundation
class Command{
func command(args: String...) -> Int32 {
let task = NSTask()
task.launchPath = "/usr/bin/env"
task.arguments = args
task.currentDirectoryPath = "/Users/Desktop/XCode/Test/"
task.launch()
task.waitUntilExit()
return task.terminationStatus
}
let xcodebuildCommand = Command()
xcodebuildCommand.command("xcodebuild","test","-project","proj.xcodeproj","-scheme","projScheme","-destination","platform=iOS Simulator,name=iPad Air"," | /usr/local/bin/xcpretty --report html --output /Desktop/test_output/report.html")
the error is
xcodebuild: error: Unknown build action ' | /usr/local/bin/xcpretty --report html --output /Desktop/test_output/report.html'.
the below command run properly from terminal:
xcodebuild test -project proj.xcodeproj.xcodeproj -scheme projScheme -destination 'platform=iOS Simulator,name=iPad Air' | xcpretty --repor html --output /pathToReportfolder/report.html
NSTask is not a shell, it will not interpret your shell script for you.
You'll need to manually set up an NSPipe to connect the standard output of your xcodebuild NSTask to an xcpretty NSTask.
import Foundation
func runCommand(workingDirectory: String? = nil,
stdin: NSPipe? = nil,
stdout: NSPipe? = nil,
stderr: NSPipe? = nil,
args: String...) -> Int32 {
let task = NSTask()
task.launchPath = "/usr/bin/env"
task.arguments = args
if let workingDirectory = workingDirectory {
task.currentDirectoryPath = workingDirectory
}
if let stdin = stdin { task.standardInput = stdin }
if let stdout = stdout { task.standardOutput = stdout }
if let stderr = stderr { task.standardError = stderr }
task.launch()
task.waitUntilExit()
return (task.terminationStatus)
}
let pipe = NSPipe()
//omit "workingDirectory:" in Swift 2
runCommand(workingDirectory: "/Users/Desktop/XCode/Test/",
stdout: pipe,
args: "xcodebuild","test",
"-project","proj.xcodeproj",
"-scheme","projScheme",
"-destination","platform=iOS Simulator,name=iPad Air")
//omit "workingDirectory:" in Swift 2
runCommand(workingDirectory: "/Users/Desktop/XCode/Test/",
stdin: pipe,
args: "/usr/local/bin/xcpretty",
"--report html",
"--output",
"/Desktop/test_output/report.html")
Related
I found std::process in document. But it seems that it cannot work. For example:
fn main() {
use std::process::Command;
let command = Command::new("command")
.arg("-sq")
.arg("ls")
.spawn()
.unwrap();
println!("{command:#?}");
}
Output:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }', 1.rs:8:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
But run the command in shell:
$ command -sq ls && echo true || echo false
true
So how can I get a output like shell in rust?
The most direct equivalent would be this:
let command = Command::new("fish")
.args(["-c", "command -sq ls"])
.output()
.unwrap();
if command.status.success() {
println!("true");
} else {
println!("false");
}
This creates a fish shell which then executes your command command. The .success() method can be used to infer if the command succeeded or failed same as && and || in your script.
I use the following code to create command which should run according to some flags that are
passed from the cli.
I use the cobra repo
https://github.com/spf13/cobra
when I run it with go run main.go echo test
I get
Print: test
which works.
Now I run go install open the
bin directory and click on the file newApp (this my name of my app)
and it prints
Usage:
MZR [command]
Available Commands:
echo Echo anything to the screen
help Help about any command
print Print anything to the screen
Flags:
-h, --help help for MZR
Use "MZR [command] --help" for more information about a command.
[Process completed]
And I cannot use any commands (like MZR echo) which I was able when I run it locally with go run main.go echo test
But I want to use it like following MZR -h or MZR echo ,
How I can do it ?
(and also give to my friend the file from the bin that created after go install - which is Unix executable - 3.8 MB )
e.g. like this repo which use the same command line tools and to run it you use hoarder --server
https://github.com/nanopack/hoarder
This is the code for example (to make it more simpler )
package main
import (
"fmt"
"strings"
"github.com/spf13/cobra"
)
func main() {
var echoTimes int
var cmdPrint = &cobra.Command{
Use: "print [string to print]",
Short: "Print anything to the screen",
Long: `print is for printing anything back to the screen.
For many years people have printed back to the screen.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdEcho = &cobra.Command{
Use: "echo [string to echo]",
Short: "Echo anything to the screen",
Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdTimes = &cobra.Command{
Use: "times [# times] [string to echo]",
Short: "Echo anything to the screen more times",
Long: `echo things multiple times back to the user by providing
a count and a string.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
for i := 0; i < echoTimes; i++ {
fmt.Println("Echo: " + strings.Join(args, " "))
}
},
}
cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
var rootCmd = &cobra.Command{Use: "MZR"}
rootCmd.AddCommand(cmdPrint, cmdEcho)
cmdEcho.AddCommand(cmdTimes)
rootCmd.Execute()
}
The name of the executable is taken from the directory name. Rename the directory newApp to MZR. With this change, the go install command will create a executable with the name MZR. If the executable is on your path, then you can run it from the command line using MZR -h or MZR echo,
First of all, my ultimate goal is to generate an html report from .plist file using xcodebuild command.
But, i am facing a problem in my osx project. My environment is
osx 10.11 el captain, xcode 7.3 and swift 2.2
I have install scan to solve this. The way to install scan
gem install scan
scan link is https://github.com/fastlane/fastlane/tree/master/scan
Now in terminal, type scan and press enter. The scan command will do the everything.
But i want to run this terminal command through my swift code. For this, i use the below code:
import Foundation
class Command{
func terminalCommand(args: String...) -> Int32 {
let task = NSTask()
task.launchPath = "/usr/bin/env"
task.arguments = args
task.currentDirectoryPath = "path to my osx project"
task.launch()
task.waitUntilExit()
return task.terminationStatus
}
}
I call this function from another swift file like bwlow:
let main = Command()
main.terminalCommand("scan")
The link is here How do I run an terminal command in a swift script? (e.g. xcodebuild)
But if i run this, it shows below error:
env: scan: No such file or directory
Than i use
which scan and it returns /usr/local/bin/scan
i add this to my code launch path
task.launchPath = "/usr/local/bin/scan"
than, if i run my swift code, it shows below error
16:50:29]: [33mxcrun xcodebuild -list -project ./ios-ui-automation-demo.xcodeproj[0m
+-----------------------+------------------------------------+
| [32mSummary for scan 0.8.0[0m |
+-----------------------+------------------------------------+
| project | ./ios-ui-automation-demo.xcodeproj |
| scheme | ios-ui-automation-demo |
| clean | false |
| code_coverage | false |
| address_sanitizer | false |
| skip_build | false |
| output_directory | ./fastlane/test_output |
| output_types | html,junit |
| buildlog_path | ~/Library/Logs/scan |
| open_report | false |
| skip_slack | false |
| slack_only_on_failure | false |
| use_clang_report_name | false |
+-----------------------+------------------------------------+
[16:50:34]: [4m[36m$ set -o pipefail && env NSUnbufferedIO=YES xcodebuild -scheme ios-ui-automation-demo -project ./ios-ui-automation-demo.xcodeproj -destination 'platform=iOS Simulator,id=841044C8-5637-4652-BDC9-3BAB05248F15' build test | tee '/Users/me/Library/Logs/scan/ios-ui-automation-demo-ios-ui-automation-demo.log' | xcpretty [0m[0m
[16:50:34]: ▸ [35mLoading...[0m
[16:50:34]: ▸ [35msh: xcpretty: command not found[0m
what is my error and why terminal command is not run in swift code as it runs well in through terminal.
please, any help or any suggestion will be highly appreciated.
One more weakness, i am not pretty expert on osx.
Thanks
At last i found a way to generate html report from .plist file.As i used scan there's an open error in scan https://github.com/fastlane-old/gym/issues/235#event-580661928
So, i tried in another way.....using xcpretty. Code is given below:
import Foundation
class command{
func runCommand(workingDirectory: String? = nil,
stdin: NSPipe? = nil,
stdout: NSPipe? = nil,
stderr: NSPipe? = nil,
args: String...) -> Int32 {
let task = NSTask()
task.launchPath = "/usr/bin/env"
task.arguments = args
if let workingDirectory = workingDirectory {
task.currentDirectoryPath = workingDirectory
}
if let stdin = stdin { task.standardInput = stdin }
if let stdout = stdout { task.standardOutput = stdout }
if let stderr = stderr { task.standardError = stderr }
task.launch()
task.waitUntilExit()
return (task.terminationStatus)
}
}
now call the funcion:
let pipe = NSPipe()
let generateHtmlReport = command()
//omit "workingDirectory:" in Swift 2.2, only use the value
generateHtmlReport.runCommand(workingDirectory: "/Users/Desktop/XCode/Test/",
stdout: pipe,
args: "xcodebuild","test",
"-project","proj.xcodeproj",
"-scheme","projScheme",
"-destination","platform=iOS Simulator,name=iPad Air")
//omit "workingDirectory:" in Swift 2.2, only use the value
generateHtmlReport.runCommand(workingDirectory: "/Users/Desktop/XCode/Test/",
stdin: pipe,
args: "/usr/local/bin/xcpretty",
"--report","html",
"--output",
"/Desktop/test_output/report.html")
I'm trying to run a command line tool and taking the result.
I checked it in terminal:
/usr/bin/exiftool -filename -directory -createdate -model "/Users/dirk/Desktop\" -t -S -q -r -f >"RenamerOutfile0.txt"
This runs fine and delivers result in file.
Using SWIFT I tried this:
let task = NSTask()
task.launchPath = "/usr/bin/exiftool"
task.arguments = ["-filename -directory -createdate -model \"/Users/dirk/Desktop\" -t -S -q -r -f"]
let pipe = NSPipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
Unfortunatly nothing happens. data is assigned 0 byte - no result.
If I insert the redirection to file no file is created.
Any idea what's the difference in calling the tool from terminal than with this task?
I found a workaround:
let x = system("/usr/bin/exiftool -filename -directory -createdate -model \"/Users/dirk/Desktop\" -t -S -q -r -f >\"/var/tmp/RenamerOutfile0.txt\"")
This works fine. Maybe because I added the path /var/tmp for output file? Doesn't matter! :-)
Is there a good description of swift system command? For example, this code
let x = system("ls -l `which which`")
println(x)
produces
-rwxr-xr-x 1 root wheel 14496 Aug 30 04:29 /usr/bin/which
0
I would like to separate the output from the return code
system() is not a Swift command but a BSD library function. You get the documentation
with "man system" in a Terminal Window:
The system() function hands the argument command to the command
interpreter sh(1). The calling process
waits for the shell to finish executing the command, ignoring SIGINT and SIGQUIT, and blocking SIGCHLD.
The output of the "ls" command is just written to the standard output and not to any
Swift variable.
If you need more control then you have to use NSTask from the Foundation framework.
Here is a simple example:
let task = NSTask()
task.launchPath = "/bin/sh"
task.arguments = ["-c", "ls -l `which which`"]
let pipe = NSPipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
if let output = NSString(data: data, encoding: NSUTF8StringEncoding) {
println(output)
}
task.waitUntilExit()
let status = task.terminationStatus
println(status)
Executing the command via the shell "/bin/sh -c command ..." is necessary here because
of the "back tick" argument. Generally, it is better to invoke the commands directly,
for example:
task.launchPath = "/bin/ls"
task.arguments = ["-l", "/tmp"]