Skip to content

Instantly share code, notes, and snippets.

@smcelhinney
Last active March 15, 2021 15:23
Show Gist options
  • Save smcelhinney/e004e535ba746afeb11c8e0724e57306 to your computer and use it in GitHub Desktop.
Save smcelhinney/e004e535ba746afeb11c8e0724e57306 to your computer and use it in GitHub Desktop.
AWS Credentials autocomplete setup.
# Append this to your ~/.bashrc or ~/.bash_profile
# Switch to a specified AWS profile globally
function aws_switch_profile() {
local profile=${1:-"default"}
export AWS_PROFILE="$profile"
}
# Setup autocomplete for the above command
setup_aws_profile_complete (){
local credentialsjson=$(<path-to-your-project>/build/index.js -f ~/.aws/credentials)
local keynames=$(echo "$credentialsjson" | jq -r 'keys[]')
complete -W "$keynames" aws_switch_profile
}
setup_aws_profile_complete

aws_switch_profile

Sets up autocomplete for switching based on your ~/.aws/credentials file.

Instructions

Note: you'll need jq installed, brew install jq should do it.

  1. Create a new typescript project, and copy the parse-credential-file.ts file into it
npm init --y && npm i yargs typescript && npm i -D @types/node @types/yargs && npx tsc --init
  1. Compile the ts file using ncc eg.
npx @vercel/ncc build parse-credential-file.ts -o build/

(The reason Im using ncc is that it allows you to move the compiled JS file into another directory without having to worry about dependencies - max portability!)

  1. Update the bashrc script above with the build path (line 11)

  2. Source your bash_profile/bashrc, eg. source ~/.bash_profile to pick up your changes

  3. Try it out! Type aws_switch_profile <TAB> in a shell.

#!/usr/bin/env node
import yargs from 'yargs/yargs'
import { existsSync, readFileSync } from 'fs'
import { resolve } from 'path'
// @ts-expect-error
import { hideBin } from 'yargs/helpers'
const { file }: any = yargs(hideBin(process.argv))
.usage('Usage: $0 -f [file]')
.demandOption(['f'])
.alias('f', 'file')
.describe('f', 'File to parse')
.argv
const parseCredentialFile = (ini: string) => {
let section: string
const out = Object.create(null)
const re = /^\[([^\]]+)\]\s*$|^([a-z_]+)\s*=\s*(.+?)\s*$/
const lines = ini.split(/\r?\n/)
lines.forEach(line => {
const match = line.match(re)
if (!match) return
if (match[1]) {
section = match[1]
// eslint-disable-next-line no-eq-null, eqeqeq
if (out[section] == null) out[section] = Object.create(null)
} else if (section) {
out[section][match[2]] = match[3]
}
})
return out
}
try {
const filePath = resolve(__dirname, file);
if (!existsSync(filePath)) {
throw new Error(`File ${filePath} does not exist`)
}
const fileAsString = readFileSync(filePath, 'utf-8');
console.log(JSON.stringify(parseCredentialFile(fileAsString), null, 2));
} catch (error) {
console.error(error)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment