ROP: Railway Oriented Programming in Swift

EXAMPLE 2: error and result aware shellCommand

TL;DR

This complete example shows how to use ROP to create a “shellCommand” utility function that is aware of bot errors (misspelled commands and exceptions) and command result (standard unix convention where:‘0’ means OK).

func countNumberOfFilesInFolder(_ folder: String) -> Result<Int> {
    return shellCommandROP("/bin/ls", [folder])
            .then(myLinesCounter)
}
printResult("1) Run on existing folder:", countNumberOfFilesInFolder("/notebooks/swift-rop/jupyter"))
printResult("2) Run on wrong folder: ", countNumberOfFilesInFolder("/wtf"))
  1. Run on existing folder: 3
  2. Run on wrong folder: ERROR: [2]: /bin/ls: cannot access ‘/wtf’: No such file or directory

In this way you can chain multiple commands

Longer chain

func countNumberOfFilesInCurrentFolder() -> Result<Int> {
    return shellCommandROP("/bin/pwd")
        .then{pwd in pwd.replacingOccurrences(of: "\n", with: "")} // Use previous result 
        .then{pwd in shellCommandROP("/bin/ls", [pwd])} // Use the clean string to search files
        .then(myLinesCounter)
}
let complexResult = countNumberOfFilesInCurrentFolder(); 
printResult("The count of number of files in ls is:", complexResult)

The count of number of files in ls is: 3

Use cases

let theFolder = "/notebooks/swift-rop/jupyter/tmp"
let theFile = theFolder + "/test.txt"
print("1) create the folder \(theFolder)",shellCommandROP("/bin/mkdir",[theFolder]))
print("2) list files in the folder",shellCommandROP("/bin/ls", [theFolder])) 
print("3) create the file \(theFile)",shellCommandROP("/bin/touch", [theFile])) 
print("4) run non existent command",shellCommandROP("/bin/wtf", [theFile])) // wtf is not a command
printResult("5) list files again. Folder content:",shellCommandROP("/bin/ls", ["-lh",theFolder])) // list files in new folder
print("6) remove the file",shellCommandROP("/bin/rm", ["-rf", theFile]))
printResult("7) Folder content:",shellCommandROP("/bin/ls", ["-lh",theFolder])) // list files in new folder
print("8) remove the folder",shellCommandROP("/bin/rmdir",[theFolder]))
print("9) try to list files in deleted folder",shellCommandROP("/bin/ls", [theFolder]))
1) create the folder /notebooks/swift-rop/jupyter/tmp Ok("")
2) list files in the folder Ok("")
3) create the file /notebooks/swift-rop/jupyter/tmp/test.txt Ok("")
4) run non existent command Error(__lldb_expr_15.SimpleError(msg: "ERROR: The operation could not be completed."))
5) list files again. Folder content: total 0
-rw-r--r-- 1 root root 0 Apr 26 15:41 test.txt

6) remove the file Ok("")
7) Folder content: total 0

8) remove the folder Ok("")
9) try to list files in deleted folder Error(__lldb_expr_21.ShellCommandError(code: 2, msg: "/bin/ls: cannot access \'/notebooks/swift-rop/jupyter/tmp\': No such file or directory\n"))

NOTE: on command (4) we have a misspell error, while on command (9) we call a correct command, but on an illegal folder (The error holds error code 2 and descriptive text).

Source code: