I am developing a shell and a language called NGS. I keep repeating it’s domain specific. What are the unique features that make NGS most suitable for today’s system administration tasks (a.k.a “Operations” or hype-compatible word “DevOps”)?
This post is first in series that show what makes NGS unique.
Execute and parse operator
Execute-and-parse operator … executes a command and parses it’s output. This one proved to be central in working with AWS API. Citing ec2din.ngs demo script:
``aws ec2 describe-instances $*filters``
The expression above returns a data structure. The command is run, the output is captured and then fed to parse()
method. Whatever the parse()
method returns is the result of the ``exec-and-parse syntax``
expression above.
Built-in parsing
By default, NGS parses any JSON output when running a command using ``exec-and-parse``
syntax. (TODO: parse YAML too)
In case with AWS CLI commands additional processing takes place to make the data structure coming out of exec-and-parse operator more useful:
- The top level of AWS responses is usually a hash that has one key which has an array as value:
{"LoadBalancerDescriptions": [NGS, returns, this] }
. While I can guess few reasons for such format, I find it much more useful to have an array as a result of running an AWS CLI command and that’s what NGS returns if you run``aws ...``
commands. - Specifically for
aws ec2 describe-instances
I’ve removed the annoyance of havingReservations
list with instances as sub-lists. NGS returns flat instances list. Sorry, Amazon, this is much more productive.
Customizable parsing
What if you have your own special command with it’s own special output format?
The parsing is customizable via defining your own parse(s:Str, hints:Hash)
method implementation. That means you can define how your command is parsed.
No parsing
Don’t want parsed data? No problem, stick with the `command`
syntax instead of ``command``
. In case you need original data structure you can use `command`.decode_json()
for example.
Why exec-and-parse is an operator?
Why adding an exec_parse()
function would not be sufficient?
- Execute-and-parse is common operation in system tasks so it should be short. NGS has taken the pragmatic approach: the more common the operation, the shorter the syntax.
- Execute-and-parse should look similar
`execute-and-capture-output`
syntax which already existed when I was adding execute-and-parse. - Making it an operator allows the command to be executed to be written in “commands syntax” (a bit bash-like) which is a better fit.
“I can add this as a function to any language!”
Sure but:
- Your chances of getting same brevity are not very good
- Making exec-and-parse as flexible as in NGS in other languages would be an additional effort
``some-command arg1 arg2``
– would it beexec_parse(['some-command', 'arg1', 'arg2'])
? How do you solve the syntax of the passed command? The array syntax does not look good here. Not many languages will allow you to have special syntax for commands to be passed toexec_parse()
.
If your language is not domain-specific for system tasks, adding exec-and-parse to it will be a task with dubious benefit.
How extreme opposite looks like
Just came across build configuration file of Firefox: settings.gradle
(sorry, could not find a link to this file on a web in a sane amount of time). Here is excerpt with lines wrapped for convenience.
def commandLine = ["${topsrcdir}/mach", "environment", "--format", "json", "--verbose"] def proc = commandLine.execute(null, new File(topsrcdir)) def standardOutput = new ByteArrayOutputStream() proc.consumeProcessOutput(standardOutput, standardOutput) proc.waitFor() ... import groovy.json.JsonSlurper def slurper = new JsonSlurper() def json = slurper.parseText(standardOutput.toString()) ... if (json.substs.MOZ_BUILD_APP != 'mobile/android') { ... }
Here is how roughly equivalent code looks in NGS (except for the new File(topsrcdir)
which I don’t understand):
json = ``"${topsrcdir}/mach" environment --format json --verbose`` ... if json.substs.MOZ_BUILD_APP != 'mobile/android' { ... }
Yes, there are many languages where exec-and-parse functionality looks like something in between Gradle and NGS. I don’t think there is one that can do what NGS does in this regard out of the box. I’m not saying NGS is better than other languages for all tasks. NGS is aiming to be better at some tasks. Dealing with I/O and data structures is definitely a target area.
Have a nice day!