[swift-corelibs-dev] Better integration with UNIX tools

Abhi Beckert me at abhibeckert.com
Sun Nov 19 21:01:59 CST 2017


> Any ideas on what form it would take? A class method on Process that
> returns the output, maybe?
I think there are two solutions, and I'd like to see both of them taken.
First of all, I disagree with Brent's assessment that we shouldn't
have a variant that "simply shells out". Even though this use case is
"discouraged" in other languages, I think in practice it definitely
has a place.
I would like swift to have something similar to PHP's backticks, with
language syntax to simply execute a shell command - maybe
somethinglike this:
> let output = #!"ls ~/Desktop -name *.png"

In the above example, the user's shell PATH variable would be used to
find the `ls` command, the tilde in in the path would be expanded, and
arguments would be split on whitespace, and output would be string with
automatically detected encoding. While this is terrible for complicated
use cases, it is appropriate for simple ones.
For a second solution to handle complex cases, the current API just
needs a lot of cleanup work – especially:
 * expanding a tilde should not require working with NSString
   (perhaps NSURL could have an option to expand tildes when created
   from a string) * It should be possible to capture the entire output of a process
   without working with NSPipe and NSFileHandle. Personally I'd prefer a
   block that is executed on completion with NSData arguments for stdout
   and stderr, but there are other options. * converting NSData to a swift string should not require working with
   NSString and it should be possible to do this with automatically
   detected encoding (NSString can do this when reading from a file,
   and CFString can do it reading from NSData. Swift strings should
   have it as well).
- Abhi

On Sat, Nov 18, 2017, at 10:47, Brent Royal-Gordon wrote:
>> On Nov 17, 2017, at 11:34 AM, Tony Parker via swift-corelibs-dev <swift-corelibs-
>> dev at swift.org> wrote:
>>
>> It does seem like there is a possibility of some better convenience
>> API here.>> 
>> Any ideas on what form it would take? A class method on Process that
>> returns the output, maybe?> 
> `Process.run(_:arguments:terminationHandler:)` is not a bad basis for
> this, other than the first argument being a URL. I might add a variant
> which does a $PATH search and expands tildes:> 
> extension Process {
> class func runInPath(_ commandName: String, with arguments: [String],
> terminationHandler: ((Process) -> Void)? = nil) -> Process> }
> 
> (I would *not* add a variant which simply shells out, or at least I
> wouldn't make it the only option. Every scripting language I can think
> of has this feature, and every one of them discourages its use and
> pushes people towards something else with pre-split arguments and no
> shell attack surface.)> 
> And then add a method which gathers all stdout output and returns it,
> along with the termination status (throwing if it's a signal):> 
> extension Process {
> func outputAfterExit() throws -> (output: String, status: Int32)
> }
> 
> The result is not *as* convenient as PHP, but it's a lot safe than
> running things through a shell, too.> 
> let (output, _) = try Task.runInPath("find", with: ["~/Desktop", "-
> name", "*.png"]).outputAfterExit()> 
> The biggest problem I see with this design is that expanding tildes in
> the arguments, but *not* globbing them, happens to be right for this
> case, but may not be in the general case. One interesting possibility
> would be to go the custom operator route:> 
> /// Returns an absolute path placing `relativePath` in the user's home
> directory.> prefix func ~ (relativePath: String) -> String {
> return FileManager.default.homeDirectoryForCurrentUser.appendingPathC-
> omponent(relativePath).path> }
> 
> let (output, _) = try Task.runInPath("find", with: [~"Desktop", "-
> name", "*.png"]).outputAfterExit()> 
> But I'm not sure we'd want that available in million-line Mac apps.
> 
> On the other hand, maybe Foundation's APIs in general are too verbose
> for scripting. I could imagine a "Foundation.Script" module which
> added some unprincipled but convenient shortcuts:> 
> extension URL: ExpressibleByStringLiteral { // Should be
> interpolatable too, but we need to redesign that.> public init(stringLiteral value: String) {
> self.init(fileURLWithPath: value)
> }
> }
> public var FS { return FileManager.default }
> public var ENV { return ProcessInfo.processInfo.environment }
> 
> That might be a good place for a leading tilde operator, too.
> 
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-corelibs-dev/attachments/20171120/fe0c6ebb/attachment.html>


More information about the swift-corelibs-dev mailing list