Re: Opening an Embedded Application in Terminal

2014-12-09 Thread SevenBits
On Tuesday, December 9, 2014, Ken Thomases k...@codeweavers.com wrote:

 On Dec 9, 2014, at 8:24 AM, SevenBits sevenbitst...@gmail.com
 javascript:; wrote:

  Do you know how to trigger the automatic flushing of standard output
 like you described? There doesn't seem to be anything in NSTask to do it,
 though it probably wouldn't be there anyway. Is it perhaps a C function
 call? I do apologize for asking a basic question, but the Internet is full
 of people wanting to get the results of a BSD-layer command, and not
 through communicating with the process via a Terminal-like interface, and
 my Google-fu is not up to the task.

 The only way to make it automatic is to have the standard input connected
 to a terminal device.  For communication between two processes, you would
 use a pseudo-terminal device:


 https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man4/pty.4.html

 https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/openpty.3.html


I actually just figured this out, but those are great; I'll certainly take
a look at them. I haven't done really low-level C stuff like that for some
time, which is why I couldn't remember the functions.


 However, that brings with it the requirement that you emulate a terminal.
 The subprocess will be able to detect that it's connected to a terminal and
 may attempt to do terminal-like things, which the parent process would have
 to expect and respond to.  That's a complicated mess.


I control the source code to the tool that is being called, and I have
modified it to make sure that no such calls are being made. This is a very
simple console application; if it needed ncurses or something of that sort
I'd be panicking right now.



 If you are building the command-line tool from source, then I recommend
 that you have it use setvbuf() to set standard output to line buffered.
 And, any place where it tries to read from standard input, call fflush() to
 flush standard output first.


Okay, thanks for the advice. I have noticed one small issue: my app
receives from the process and prints back all of the app's input. That, and
the app's outputs are buffered, so in some cases it takes a while for its
output to reach my terminal, making it appear to be hanging, but that's a
minor issue.



 Regards,
 Ken


Thanks a lot everyone'

-- SevenBits
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Opening an Embedded Application in Terminal

2014-12-08 Thread Lee Ann Rucker

On Dec 7, 2014, at 4:42 PM, Keary Suska cocoa-...@esoteritech.com wrote:

 On Dec 7, 2014, at 1:35 PM, SevenBits sevenbitst...@gmail.com wrote:
 
 
 I don't know if this approach is more likely to work in a sandboxed app.  I 
 doubt it, because it would be an enormous hole in the sandbox.  If you can 
 direct Terminal to run arbitrary commands, what protection does the sandbox 
 provide?
 
 I get your point, but the fact is, I’m not trying to run an arbitrary 
 command, and I don’t even care if Terminal inherits the sandbox from my 
 process. I just need to run this command in a window so that the user can 
 type input in and receive the results back. In other words, I’m looking for 
 Terminal’s user interface, not its ability to run arbitrary commands.
 
 If it matters, the executable is a program that evaluates instructions using 
 REPL (read-eval-print loop).
 
 
 
 I really need this to work as it’s an important aspect of my application. 
 Can anyone advise?
 
 I suspect you have a serious problem, then.  You will probably need to 
 deploy outside of the Mac App Store so that you don't have to sandbox your 
 app.  Alternatively, you can build a terminal emulator UI into your app and 
 run the embedded console program within that, instead of Terminal.  
 Depending on the needs of your console program, that may be a relatively 
 straightforward prospect or a very complex one.
 
 Well, I’m stuck in the middle. On the one hand, implementing a full-brown 
 terminal emulator along the lines of iTerms 2 for my app is overkill and 
 isn’t worth the extra megabytes. But I don’t want to implement a kludgy 
 NSTextField-based interface to feed in input using NSTask and output/input 
 streams either, as it doesn’t look that great.
 
 However, unless someone can come up with a good way to provide a 
 Terminal-like environment for REPL applications, the second approach is the 
 one I’ll probably have to take…
 
 I would first try NSTextView instead--you get a lot of control simply from 
 delegate calls, although you will need to subclass. The only tricky part is 
 how to handle the parts that would not be editable, and what to do when 
 someone tries to edit it. Setting a custom attribute is probably the way to 
 go.


The TextViewDelegate sample app shows how to handle that
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Opening an Embedded Application in Terminal

2014-12-07 Thread Ken Thomases
On Dec 7, 2014, at 2:29 PM, SevenBits sevenbitst...@gmail.com wrote:

 I have a sandboxed app destined for the Mac App Store. Inside of it is an 
 embedded console program which I want to open in Terminal (i.e Terminal.app 
 opens and the app runs in its window). Here’s what I’m doing:
 
 NSString *interactiveExecutablePath = [[[NSBundle mainBundle] bundlePath] 
 stringByAppendingPathComponent:@/Contents/MacOS/app];
 [NSTask launchedTaskWithLaunchPath:@/usr/bin/open arguments:@[@-a, 
 @Terminal, interactiveExecutablePath]];

First, it never makes any sense for a program to spawn a subprocess to run 
/usr/bin/open.  /usr/bin/open is just a wrapper around Launch Services.  So, 
you could just call Launch Services directly or use NSWorkspace, which is also 
a wrapper around Launch Services.

Second, even using Launch Services isn't the best way to do this (sandbox 
issues aside).  It's better to run the equivalent of this AppleScript script:

tell app Terminal
activate
do script your command goes here
end

You can do that using NSAppleScript or the Scripting Bridge.

I don't know if this approach is more likely to work in a sandboxed app.  I 
doubt it, because it would be an enormous hole in the sandbox.  If you can 
direct Terminal to run arbitrary commands, what protection does the sandbox 
provide?


 I really need this to work as it’s an important aspect of my application. Can 
 anyone advise?

I suspect you have a serious problem, then.  You will probably need to deploy 
outside of the Mac App Store so that you don't have to sandbox your app.  
Alternatively, you can build a terminal emulator UI into your app and run the 
embedded console program within that, instead of Terminal.  Depending on the 
needs of your console program, that may be a relatively straightforward 
prospect or a very complex one.

Regards,
Ken


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Opening an Embedded Application in Terminal

2014-12-07 Thread SevenBits

 On Dec 7, 2014, at 4:03 PM, Ken Thomases k...@codeweavers.com wrote:
 
 On Dec 7, 2014, at 2:29 PM, SevenBits sevenbitst...@gmail.com wrote:
 
 I have a sandboxed app destined for the Mac App Store. Inside of it is an 
 embedded console program which I want to open in Terminal (i.e Terminal.app 
 opens and the app runs in its window). Here’s what I’m doing:
 
 NSString *interactiveExecutablePath = [[[NSBundle mainBundle] bundlePath] 
 stringByAppendingPathComponent:@/Contents/MacOS/app];
 [NSTask launchedTaskWithLaunchPath:@/usr/bin/open arguments:@[@-a, 
 @Terminal, interactiveExecutablePath]];
 
 First, it never makes any sense for a program to spawn a subprocess to run 
 /usr/bin/open.  /usr/bin/open is just a wrapper around Launch Services.  So, 
 you could just call Launch Services directly or use NSWorkspace, which is 
 also a wrapper around Launch Services.
 
 Second, even using Launch Services isn't the best way to do this (sandbox 
 issues aside).  It's better to run the equivalent of this AppleScript script:
 
 tell app Terminal
activate
do script your command goes here
 end
 
 You can do that using NSAppleScript or the Scripting Bridge.

Okay, but out of curiosity, what makes AppleScript a better choice in this 
scenario? Doesn’t it ultimately fall back on Launch Services just like the 
other options?

 
 I don't know if this approach is more likely to work in a sandboxed app.  I 
 doubt it, because it would be an enormous hole in the sandbox.  If you can 
 direct Terminal to run arbitrary commands, what protection does the sandbox 
 provide?

I get your point, but the fact is, I’m not trying to run an arbitrary command, 
and I don’t even care if Terminal inherits the sandbox from my process. I just 
need to run this command in a window so that the user can type input in and 
receive the results back. In other words, I’m looking for Terminal’s user 
interface, not its ability to run arbitrary commands.

If it matters, the executable is a program that evaluates instructions using 
REPL (read-eval-print loop).

 
 
 I really need this to work as it’s an important aspect of my application. 
 Can anyone advise?
 
 I suspect you have a serious problem, then.  You will probably need to deploy 
 outside of the Mac App Store so that you don't have to sandbox your app.  
 Alternatively, you can build a terminal emulator UI into your app and run the 
 embedded console program within that, instead of Terminal.  Depending on the 
 needs of your console program, that may be a relatively straightforward 
 prospect or a very complex one.

Well, I’m stuck in the middle. On the one hand, implementing a full-brown 
terminal emulator along the lines of iTerms 2 for my app is overkill and isn’t 
worth the extra megabytes. But I don’t want to implement a kludgy 
NSTextField-based interface to feed in input using NSTask and output/input 
streams either, as it doesn’t look that great.

However, unless someone can come up with a good way to provide a Terminal-like 
environment for REPL applications, the second approach is the one I’ll probably 
have to take…

Thanks,

— SevenBits

 
 Regards,
 Ken
 



signature.asc
Description: Message signed with OpenPGP using GPGMail
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Opening an Embedded Application in Terminal

2014-12-07 Thread Keary Suska
On Dec 7, 2014, at 1:35 PM, SevenBits sevenbitst...@gmail.com wrote:

 
 I don't know if this approach is more likely to work in a sandboxed app.  I 
 doubt it, because it would be an enormous hole in the sandbox.  If you can 
 direct Terminal to run arbitrary commands, what protection does the sandbox 
 provide?
 
 I get your point, but the fact is, I’m not trying to run an arbitrary 
 command, and I don’t even care if Terminal inherits the sandbox from my 
 process. I just need to run this command in a window so that the user can 
 type input in and receive the results back. In other words, I’m looking for 
 Terminal’s user interface, not its ability to run arbitrary commands.
 
 If it matters, the executable is a program that evaluates instructions using 
 REPL (read-eval-print loop).
 
 
 
 I really need this to work as it’s an important aspect of my application. 
 Can anyone advise?
 
 I suspect you have a serious problem, then.  You will probably need to 
 deploy outside of the Mac App Store so that you don't have to sandbox your 
 app.  Alternatively, you can build a terminal emulator UI into your app and 
 run the embedded console program within that, instead of Terminal.  
 Depending on the needs of your console program, that may be a relatively 
 straightforward prospect or a very complex one.
 
 Well, I’m stuck in the middle. On the one hand, implementing a full-brown 
 terminal emulator along the lines of iTerms 2 for my app is overkill and 
 isn’t worth the extra megabytes. But I don’t want to implement a kludgy 
 NSTextField-based interface to feed in input using NSTask and output/input 
 streams either, as it doesn’t look that great.
 
 However, unless someone can come up with a good way to provide a 
 Terminal-like environment for REPL applications, the second approach is the 
 one I’ll probably have to take…

I would first try NSTextView instead--you get a lot of control simply from 
delegate calls, although you will need to subclass. The only tricky part is how 
to handle the parts that would not be editable, and what to do when someone 
tries to edit it. Setting a custom attribute is probably the way to go.

HTH,

Keary Suska
Esoteritech, Inc.



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Opening an Embedded Application in Terminal

2014-12-07 Thread Ken Thomases
On Dec 7, 2014, at 5:35 PM, SevenBits sevenbitst...@gmail.com wrote:

 On Dec 7, 2014, at 4:03 PM, Ken Thomases k...@codeweavers.com wrote:
 
 Second, even using Launch Services isn't the best way to do this (sandbox 
 issues aside).  It's better to run the equivalent of this AppleScript script:
 
 tell app Terminal
   activate
   do script your command goes here
 end
 
 You can do that using NSAppleScript or the Scripting Bridge.
 
 Okay, but out of curiosity, what makes AppleScript a better choice in this 
 scenario? Doesn’t it ultimately fall back on Launch Services just like the 
 other options?

Not exactly.  AppleScript will use Launch Services to launch Terminal if it's 
not already running, but not otherwise.  And Launch Services delivers Apple 
Events to tell Terminal to open a document.

The reason I consider the Apple Script (or Scripting Bridge) approach to be 
better is that it is more specific to what you're trying to do.  It's not at 
all clear to me that opening an executable with Terminal is going to 
_reliably_ run that executable's path as a command in a new window.  Directly 
telling Terminal to run a particular command with its AppleScript interface 
seems much closer to the specific thing you're trying to accomplish.


 I don't know if this approach is more likely to work in a sandboxed app.  I 
 doubt it, because it would be an enormous hole in the sandbox.  If you can 
 direct Terminal to run arbitrary commands, what protection does the sandbox 
 provide?
 
 I get your point, but the fact is, I’m not trying to run an arbitrary 
 command, and I don’t even care if Terminal inherits the sandbox from my 
 process.

If Terminal is already running, it won't inherit your sandbox.

 I just need to run this command in a window so that the user can type input 
 in and receive the results back. In other words, I’m looking for Terminal’s 
 user interface, not its ability to run arbitrary commands.

There's no separating Terminal from its ability to run arbitrary commands.  
There's certainly no way that the system is going to have the insight into what 
you're doing to understand that it should be allowed.  There are too many 
layers of indirection and interpretation of arguments.

Among other things, any Terminal window is going to run a login shell, which is 
going to process /etc/profile and one of ~/.bash_profile, ~/.bash_login, or 
~/.profile.

 If it matters, the executable is a program that evaluates instructions using 
 REPL (read-eval-print loop).

I'm guessing it doesn't need much in terms of terminal emulation.  I.e. it's 
not using curses/ncurses, terminal control, color, etc.  In that case, it may 
be a good candidate for driving via NSTask and pipes.  You will want to make 
sure that it flushes standard output before blocking waiting for input.  That's 
automatic when standard input and output are connected to a terminal device, 
but not when they're connected to pipes.

Regards,
Ken


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com