> On Nov 17, 2017, at 11:34 AM, Tony Parker via swift-corelibs-dev 
> <swift-corelibs-dev@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.appendingPathComponent(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

_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev

Reply via email to