Skip to content

Instantly share code, notes, and snippets.

@ptbrowne
Last active July 23, 2019 08:28
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 ptbrowne/f697899b2212757f4b857d794e48ea30 to your computer and use it in GitHub Desktop.
Save ptbrowne/f697899b2212757f4b857d794e48ea30 to your computer and use it in GitHub Desktop.
Simple command cache

If you deal with commands that can take several seconds but always return the same result and you need to transform the result with pipe chain (jq / grep / awk), it can be annoying to wait for those seconds while you incrementally build the command, when you know the result has not changed.

cache.js can help you by caching the result of the command to /tmp and returning the result immediately.

Installation

wget https://gist.githubusercontent.com/ptbrowne/f697899b2212757f4b857d794e48ea30/raw/9b6e96506e2c3b0c64bceea70302f5597c452272/cache.js -O ~/bin/cache
chmod +x ~/bin/cache

I used ~/bin/ because this directory is already in my PATH but you can use any directory that is in your PATH.

Usage

cache "decorates" the command you give it.

- ./long-command input-file.json --my-arg 
+ cache ./long-command input-file.json --my-arg 

How does it work

cache makes an array out of all the arguments (name + index), JSON stringifies it, hashes it to make a <key>, and looks for /tmp/<key>. If the file exists, it outputs its content (max length 10Mo).

Additionally, an extra step is taken to handle file arguments. For each argument, we check a file with the same name exists and if it exists, the modification time is added to information of the argument. If the file changes, the <key> changes and the result of the command is recomputed.

#!/usr/bin/env node
const fs = require('fs')
const child_process = require('child_process')
const crypto = require('crypto')
const args = process.argv.slice(2)
const withCacheInfo = args.map((argName, argIndex) => {
return {
argName,
argIndex,
mtime: fs.existsSync(argName) ? fs.statSync(argName).mtime : undefined
}
})
const cacheKey = JSON.stringify(withCacheInfo, null, 2)
const hash = crypto.createHash('md5').update(cacheKey).digest("hex")
const filename =`/tmp/${hash}-cache`
if (fs.existsSync(filename)) {
console.log(fs.readFileSync(filename).toString())
} else {
child_process.exec(args.join(' '), { maxBuffer: 1024*1024*1024 }, (error, stdout) => {
if (error) {
console.error(error)
process.exit(1)
} else {
fs.writeFileSync(filename, stdout)
console.log(stdout)
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment