Using NSTask to launch a Ruby script (Shenzhen) - objective-c

I am trying to generate an IPA with the Shenzhen script: https://github.com/nomad/shenzhen
Here is the code I currently have:
-(void)startBuildIPAForProject:(NSString*)path
{
task = [[NSTask alloc] init];
[task setLaunchPath:#"/bin/bash"];
[task setCurrentDirectoryPath:path];
[task setArguments:#[#"ipa build",#"-c",#"Release"]];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding];
NSLog(#"task output: %#",string);
[task waitUntilExit];
}
When executing [task launch] I get the following output from the console:
/bin/bash: ipa build: No such file or directory
When I use the regular terminal ipa build is working (that is, it tells me there exists no Xcode project in the current dir)
I'm a bit lost, so any help is greatly appreciated.

The ipa script will need to be in your application's PATH environment variable (or in the same directory as your binary.) An easy fix would be to specify the full, absolute path to ipa in your arguments. i.e. change:
[task setArguments:#[#"ipa build",#"-c",#"Release"]];
to
[task setArguments:#[#"/full/path/to/ipa build",#"-c",#"Release"]];

Related

How to read macOS desktop file in cocoa app

I want to make cocoa app execute .sh file or other Operation,
this my code:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#",[self cmd:#"cd Desktop;ls;"]);
}
- (NSString *)cmd:(NSString *)cmd
{
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/bash"];
NSArray *arguments = [NSArray arrayWithObjects: #"-c", cmd, nil];
[task setArguments: arguments];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
NSData *data = [file readDataToEndOfFile];
return [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
}
but log error:
ls: .: Operation not permitted
how to do that?I search about macOS permit,Do I need use SMJobBless ?
Sandbox applications aren't allowed to read outside the application folder. So in order for your script to work you need to turn off Sandbox.
Also you need to change the path like Sangram S. mentioned or set the current directory to the home folder:
[task setCurrentDirectoryPath:NSHomeDirectory()];
change
NSLog(#"%#",[self cmd:#"cd Desktop;ls;"]);
with
NSLog(#"%#",[self cmd:#"cd ~/Desktop; ls;"]);

Executing a command from Objective C

I want to execute a command from objective C (Cocoa framework). The command I am trying is as below. I tried with NSTask but it says "launch path not accessible" when I execute it.
sudo ifconfig en0 down
My code is:
- (void)testme {
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"sudo ifconfig en0 down"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: #"foo", #"bar.txt", nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog (#"command returned:\n%#", string);
[string release];
[task release];
}
sudo ifconfig en0 down is not a sensible launch path. The correct launch path for this command would be /usr/sbin/sudo.
Once that is done, you still need to pass the correct arguments to setArguments:. foo and bar.txt look like example code that you copied without reading.
MORE IMPORTANTLY, THOUGH, running sudo from NSTask will not work. You will need to use Authorization Services to launch a privileged command.
You need to specify the full executable path and you should specify the arguments as the arguments, not along with the launch path. NSTask ain't a shell, it internally uses syscalls (execv(), I guess) to invoke the command.
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/usr/bin/sudo"];
NSArray *arguments = #[#"ifconfig", #"en0", #"down"];
[task setArguments:arguments];

Call shell script with argument in Mac application

I'm having trouble calling a shell script which takes an argument from my Cocoa application for Mac.
I have created the shell script, and put it in the app's local repository. It is called SCRIPT. It takes one argument which is a URL address.
I call the script as follows but nothing happens, no errors or messages, just the script stops after doing nothing.
NSString *address = [_addressField stringValue];
NSString *resPath = [[NSBundle mainBundle] resourcePath];
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: [NSString stringWithFormat:#"%#/SCRIPT", resPath]];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: address, nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *status;
status = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog (#"%#", status);
Thanks in advance everyone
The Objective-C code seams to work fine for me if i try with /bin/echo as launch path. So i guess the problem is with the script. Can you include the script in your question? note that the environment when running from a Cocoa application is probably quite different from when running in a interactive shell.
Could it be a permissions issue? Try invoking /bin/sh and setting the script path as the first argument.

Run terminal command with NSTask

I want to run a Terminal command in my program.
The command looks like this:
cd /path/to/file/; ./foo HTTPProxy 127.0.0.1
It works with system() but it doesn't work when I use NSTask.
system("cd /path/to/file/; ./foo HTTPProxy 127.0.0.1");
works fine but
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/path/to/file/./foo"];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task setArguments:[NSArray arrayWithObjects:#"HTTPProxy 127.0.0.1", nil]];
[task launch];
NSData *data = [file readDataToEndOfFile];
NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(string);
doesn't.
Output:
Command-line option 'HTTPProxy 127.0.0.1' with no value. Failing.
Has anybody an idea?
Now I think I have got it:
[task setArguments:[NSArray arrayWithObjects:#"HTTPProxy", #"127.0.0.1", nil]];
those are separate arguments in your invocation from the command line...
OLD ANSWER:
You could trying setting the current directory for execution:
– setCurrentDirectoryPath:
This is basically the effect of cd in the system version of your code.

Running multiple NSTasks consecutively

I need to run multiple commands in sequence using NSTask and was wondering what would be a good way to tell if a task has finished so I can continue on to the next command. I'm using "sox" (which I am including in my application bundle) to create temporary audio files using input audio files, and then need to combine those temporary audio files into a single file. An example of the flow of processes (not the actual commands):
1) songA > tempA
2) songB > tempB
3)combine tempA tempB > songC
I'm using the following code to complete the first command:
NSArray *arguments;
arguments = [NSArray arrayWithObjects: #"songA", #"-f", #"-S", #"-G", #"-V", #"-b", #"24", #"-r", #"384k", #"tempA", nil];
NSString *path=[[NSBundle mainBundle] pathForResource:#"sox" ofType:nil];
NSTask *task;
task = [[NSTask alloc] init];
[task setStandardInput:[NSPipe pipe]];
[task setLaunchPath:path];
[task setArguments: arguments1];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog (#"stuff :\n%#", string);
[string release];
[task release];
Suppposing I needed to perform two more NSTask processes after this one had finished (using the output of the previous processs), what would be the best way to detect that one process has finished so that I can continue on to the next one.
Thanks.
Maybe not understand fully, but
[task waitUntilExit];
does not do the job?