Re: Opening an Embedded Application in Terminal
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
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
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
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
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
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