DEV Community

Cover image for Shareable CLI demo?
Ben Lovy
Ben Lovy

Posted on

Shareable CLI demo?

Hi folks!

Over the weekend I was enlisted to produce a proof of concept demo, to pitch as part of a project proposal presentation. Perfect!

I did so, and they're happy (pleased?) with the result. The demo I've produced is a CLI application that reads an input file from the filesystem specified at runtime. It outputs to stdout and takes input from stdin. Very barebones demo. I implemented this program in Rust, and suffices for this purpose. They are planning to screenshare during the presentation to show off the capability.

However, it would be ideal if there were some way to share this demo easily - they could just provide a URL and get something to play with.

Options I've considered:

1) Refactor into a WASM module, build a very simple JS webapp with DOM elements for inputs and outputs. I've started doing this, but it's non-trivial.
2) Throw the whole thing on a DigitalOcean droplet and let people ssh to the box.
3) Re-implement the whole thing in JavaScript.

I will not be doing #3, this demo has a total useful life of a single day, and it's not worth the effort. If the project is picked up, we're starting from scratch.

I did take a stab at #1, but it's not straightforward. I hadn't anticipated this need, so it's not a completely straightforward refactor to also not break the current stdout/stdin functionality. I think this is the nicest option, but it is not simple to produce from my current code in one day. With a little more time, this is absolutely what I would do, but I don't want to rush it.

That leaves me with #2, but I don't really know how safe or reasonable that is. What I'm thinking is that I'd just pop the compiled executable on a droplet with all the demo input files there ready to go, and then users could log in remotely and execute from there. Is that horrendous?

Pressure is low - what I've produced to date will be fine, this is a nice-to-have that would be great to deliver. I've only got this afternoon to pull it together, though, so complexity needs to be low.

How would you solve this problem?

Aside: one of my first ever billable pieces of work was in Rust and I am just over the moon about that.

Photo by Thomas Jensen on Unsplash

Latest comments (30)

Collapse
 
marceloandrade profile image
Marcelo Andrade R.

I think this can work fine: github.com/joewalnes/websocketd

Collapse
 
deciduously profile image
Ben Lovy

Whoa, more than fine. Looks like a one-stop solution. Never heard of this, thank you so much.

Collapse
 
ehorodyski profile image
Eric Horodyski

Why don't you have an interactive session this afternoon where you poll the audience and use their prompts? You might be solving a problem you don't have.

And if they want to play with it, buy yourself time after the demo. 1) you have limited time 2) you don't want to disengage them from the presentation

Collapse
 
deciduously profile image
Ben Lovy

This would be the best solution if I had access to the audience. I'm remote and will not be the one giving the presentation tomorrow.

I think the eventual solution here will be to pont them to download a zip file with a precompiled bundle. Not quite a seamless as a URL, but that's already done and will work in about three clicks.

Collapse
 
ehorodyski profile image
Eric Horodyski

Why are you giving them access to it anyway? I understand wanting to wow the audience, but at the same time you risk your IP with your idea, no?

Thread Thread
 
deciduously profile image
Ben Lovy

No real IP risk. This is an engineering unit pitching a project to their own company.

Collapse
 
gypsydave5 profile image
David Wickes • Edited

If it's reading from stdin and spitting out on stdout...

Option 4

... can't you just hook it up to a route on a web server?

That way people could 'demo' it using curl.

Or you could build a thin web frontend using a smidgen of vanilla JavaScript.

Collapse
 
deciduously profile image
Ben Lovy

I could if it were just crunching an input and spitting an output, but it runs the user through a series of interactive prompts. I don't think curl is suited for this, could be wrong?

Collapse
 
gypsydave5 profile image
David Wickes • Edited

Yup, curl won't cut it.

Are the prompts for 'configuration' only? If so you could still stick it on a server, but take some querystring params for the options (built into a web page UI), then do the major work server side.

Another option... perform the interaction over TCP instead of HTTP - now you can use netcat to demo it.

Thread Thread
 
gypsydave5 profile image
David Wickes • Edited

Another option... perform the interaction over TCP instead of HTTP - now you can use netcat to demo it.

(I like this idea so much I almost want to write a 'framework' for it...)

  • start a TCP listener
  • on connection, start the cli tool in a separate process
  • hook stdin and stdout of the tool to the TCP connection
  • ????
  • PROFIT
Thread Thread
 
deciduously profile image
Ben Lovy

The WASM thing is absolutely overkill, with you there 100%.

Are the prompts for 'configuration' only?

Not really - the prompts are the main event. It builds a branching tree of prompts from the input file provided, and can refer to previously received responses.

The "real" option would be to ditch text prompts and build graphical widgets, which sounds fun, too, but not a one-day thing.

Thread Thread
 
deciduously profile image
Ben Lovy

This definitely sounds like it fits. I've never mucked about with TCP before but I don't think there's anything in my way conceptually, at least.

Thread Thread
 
gypsydave5 profile image
David Wickes

I've just scrapped around with this in Go - I'm sure you can convert to Rust with ease - using cowsay as the target command line app:

package main

import (
    "fmt"
    "net"
    "os"
    "os/exec"
)

func main() {
    listen, err := net.Listen("tcp", "127.0.0.1:6000")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    conn, err := listen.Accept()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    cmd := exec.Command("cowsay")
    cmd.Stdin = conn
    cmd.Stdout = conn
    cmd.Start()
    cmd.Wait()
}
Thread Thread
 
deciduously profile image
Ben Lovy

/thread

Above and beyond, David, thanks for the sample!

That might be exactly the ticket - no real need to translate to Rust, I might just start with your Go template if you don't mind, that looks like less friction.

Collapse
 
jeikabu profile image
jeikabu

Maybe Live Share? I keep trying to find excuses to use that...

Collapse
 
deciduously profile image
Ben Lovy

This is interesting, might fit. Thanks, never heard of this.

Collapse
 
ehorodyski profile image
Eric Horodyski

You'd have to have your demo users running VS Code though.

Thread Thread
 
deciduously profile image
Ben Lovy

True. I know some will, but likely not all. And if I'm requiring them to install something, they may as well just download my precompiled bundle from github.

Thread Thread
 
ehorodyski profile image
Eric Horodyski • Edited

Looking through this post and replies... If I were you I'd focus on making sure the demo is solid and doesn't break. And record a backup if something fails during the presentation.

What you want to do doesn't seem worth the sweat equity at this time

Collapse
 
charlesdlandau profile image
Charles Landau

When I hear "demo" and "low effort" I immediately think of zeit and netlifly. I haven't tried them with Rust, but in many cases you can deploy your code as an endpoint and curl against it with very little effort.

Collapse
 
deciduously profile image
Ben Lovy

Oh, that's cool! I've heard of these platforms but not used either, will definitely take a look. Thank you!

Collapse
 
charlesdlandau profile image
Charles Landau

I looked it up and unfortunately there's no Rust support, so you'll still be doing the WASM two-step if you go this route.

Thread Thread
 
deciduously profile image
Ben Lovy

Oh wow, thanks for the research. Good to know.

I think the WASM<->JS app I'm building will work, and I do think I can deliver in a (long) day, but it felt like I was overthinking what sounds like a simple ask.

Collapse
 
awwsmm profile image
Andrew (he/him) • Edited

Have you considered repl.it?

Collapse
 
deciduously profile image
Ben Lovy

Ah, shoot - looks like they don't support external dependencies for Rust, and I'm leaning on a parsing library.

Collapse
 
awwsmm profile image
Andrew (he/him)

Can you cut and paste the relevant bits into a file? And include that file?

Thread Thread
 
deciduously profile image
Ben Lovy

I'll play with it, but I think I need to be able to pull in the parsing crate to the build. It would probably be feasible to implement parsing by hand now that I've figured out the file format, which solves the problem, but not quickly.

Thread Thread
 
awwsmm profile image
Andrew (he/him)

Better than rewriting the whole thing in JavaScript, though?

Thread Thread
 
deciduously profile image
Ben Lovy

Heh. How so very right you are.

Collapse
 
deciduously profile image
Ben Lovy

Ah jeeze, you may have just completely solved this problem. I didn't realize you could include other files to read!

I think I owe you a beer or something.