Skip to content

Instantly share code, notes, and snippets.

@mikehearn
Last active February 15, 2023 15:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikehearn/5d960e1dae16ca358ccff07679f45aa3 to your computer and use it in GitHub Desktop.
Save mikehearn/5d960e1dae16ca358ccff07679f45aa3 to your computer and use it in GitHub Desktop.
#!/usr/bin/env hshell
// -------------------- Dependencies and imports ------------------------------------------------
//
// You can depend on Maven coordinates, they will be downloaded and cached in ~/.m2 automatically.
@file:DependsOn("com.github.ricksbrown:cowsay:1.0.0")
import com.github.ajalt.mordant.table.table
import com.github.ricksbrown.cowsay.Cowsay
import hydraulic.utils.os.runningOnWindows
import org.tinylog.kotlin.Logger.debug
import org.tinylog.kotlin.Logger.info
import org.tinylog.kotlin.Logger.trace
import org.tinylog.kotlin.Logger.warn
// -------------------- Formatted text output --------------------------------------------------------
//
// You can render Markdown to the terminal.
echomd("""
# Hydraulic Shell Demo
HShell can render Markdown. You can make [clickable hyperlinks](https://hydraulic.software) if your terminal supports them.
""")
// Notices will be rendered with a nice emoji when possible, colored, word wrapped and logged at the appropriate level.
val lipsum = "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"
echo(Info("Some information. $lipsum"))
echo()
echo(Warning("A warning. $lipsum"))
echo()
echo(Error("An error. $lipsum"))
// But you may wish to have more direct control. See https://github.com/ajalt/mordant for what's available. Any Widget can be passed to
// echo. Text can be styled using colors and styles from TextStyles and TextColors.
echo()
echo(red("This will be rendered in red."))
echo("${bold("Something important:")} Something less important.")
echo()
echo("Tables work:")
echo(table {
header { row("CJK", "Emojis") }
body { row("모ㄹ단ㅌ", "🙊🙉🙈") }
})
echo()
// And you can mix them:
echomd("""
1. A numbered list.
1. Another entry, ${dim("with something less visible.")}
""")
// -------------------- Logging -----------------------------------------------------------------
//
// Run hshell --show-log to view script logs. Note that if the script was compiled you may see internal logging related to that.
// You can use -v or -vv to show more detail.
echomd("""
## Logging
If you can't see anything in this section, try running `hshell -v ./demo.shell.kts` and add more `-v` flags to see more detail.
""")
trace("Logged trace!")
debug("Logged debug!")
info("Logged info!")
warn("Logged warning!")
Logger.error("Logged error!")
// -------------------- Script arguments --------------------------------------------------------
//
// Any collection can have bulletedList() applied to it, which uses Unicode bullets.
// We can read CLI arguments to the script as a list of strings, if we want custom parsing.
/** Arguments that didn't match any PicoCLI option or parameter field. */
@Unmatched var unmatchedArguments: List<String> = ArrayList()
echomd("""
## Argument parsing
Raw arguments are:
${arguments.bulletedList()}
Unmatched arguments are: ${unmatchedArguments.joinToString().takeIf { it.isNotBlank() } ?: "(none)"}
""")
// But it's MUCH easier to define flags using PicoCLI, like this:
@Option(names = ["--think", "-t"], description = ["Thought bubble?"])
var think: Boolean = false
@Parameters(index = "0", description = ["Name to greet"])
lateinit var name: String
echo()
echo(if (think) Cowsay.think(arrayOf("Hmm is that $name?")) else Cowsay.say(arrayOf("Hello $name!")))
// -------------------- Shell API --------------------------------------------------------------
//
echomd("""
## Shell API
You can explore [the Shell API](https://www.hq.hydraulic.software/api/hydraulic.internal.shell/hydraulic.shell/-shell/index.html) in our
developer docs.
**Printing a collection of paths gives an `ls` like rendering:** `ls("/")`:
""")
echo()
echo(ls("/"))
echo()
echomd("""
**First line of this script is:**
${read(scriptFilePath).splitToLineSequence().first()}
**All hshell scripts in this directory:**
${ls("${scriptDirPath}/**.shell.kts").bulletedList(bullet = "- ")}
**SHA256 of this script:** ${sha256(scriptFilePath)}
""")
echo()
// cd + block will restore the cwd after the block finishes.
// mktmp() creates a dir that's cleaned up after the script ends.
cd(mktmp()) {
wget("https://google.com/robots.txt")
echo("The first five lines of the Google robots.txt file are:\n" + readLines("robots.txt").take(5))
}
// There's also chmod, base64, cp, diff, patch, du, exists, find, ln, xattr, parallelWalk, rm, tar, touch, tree, zip/unzip, etc.
echo()
if (runningOnWindows) {
echo(markdown("Executing `ipconfig`"))
"ipconfig"()
} else {
echomd("Executing `ifconfig` and taking the last 20 lines")
// tail -nXXX is a bit more verbose.
// TODO(low): Add a Shell helper to shorten this, as wanting lines/strings is such a common thing.
("ifconfig".get() as List<String>).takeLast(20).forEach { echo(it) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment