Skip to content

Instantly share code, notes, and snippets.

@Kenterfie
Created August 1, 2023 18:43
Show Gist options
  • Save Kenterfie/a7ec9e50f17a749b8bb6469f21a6be4f to your computer and use it in GitHub Desktop.
Save Kenterfie/a7ec9e50f17a749b8bb6469f21a6be4f to your computer and use it in GitHub Desktop.
Small python script to make terraform plan outputs for terraform helm_release values better readable
#!/bin/env python3
#
# TERRADIFF
#
# Small script to convert EOT diffs into single line diffs to make them easier to read
#
# How to use
# terraform plan | terradiff
#
import re
import sys
import difflib
from os import isatty
try:
from colorama import Fore, Back, Style, init
init()
except ImportError: # fallback so that the imported classes always exist
class ColorFallback():
__getattr__ = lambda self, name: ''
Fore = Back = Style = ColorFallback()
def color_diff(diffc):
for line in diffc:
if line.startswith('+'):
yield Fore.GREEN + line + Fore.RESET
elif line.startswith('-'):
yield Fore.RED + line + Fore.RESET
elif line.startswith('^'):
yield Fore.BLUE + line + Fore.RESET
else:
yield line
def strip_ansi_codes(s):
"""
Remove ANSI color codes from the string.
"""
return re.sub('\033\\[([0-9]+)(;[0-9]+)*m', '', s)
is_pipe = not isatty(sys.stdin.fileno())
if not is_pipe:
raise SystemExit("No input available. Please use 'command | terradiff'")
input = sys.stdin.read()
# Colored version
r = r'.\[31m(-).\[0m.\[0m (<<-EOT.*?EOT).*?.\[32m(\+).\[0m.\[0m (<<-EOT.*?EOT)'
for match in re.finditer(r, input, re.S):
d = difflib.Differ()
l = match.group(2)
r = match.group(4)
lc = strip_ansi_codes(l)
rc = strip_ansi_codes(r)
diff = d.compare(lc.splitlines(keepends=True), rc.splitlines(keepends=True))
input = input.replace(match.group(0), ''.join(color_diff(diff)))
# Raw version
r = r'(-) (\<\<-EOT.*?EOT).*?(\+) (\<\<-EOT.*?EOT)'
for match in re.finditer(r, input, re.S):
d = difflib.Differ()
diff = d.compare(match.group(2).splitlines(keepends=True), match.group(4).splitlines(keepends=True))
input = input.replace(match.group(0), ''.join(diff))
print(input)
@yahel2410
Copy link

Life changer! 🙌

@someshkoli
Copy link

Thanks for this. Made some upgrades for my usecase. I found that this one is pure string diff, In case there are log of changes and movements in yaml file it'll be tough to figureout what's changed and what is not.
Sorting yaml solves this, small snippet attached below to take in yaml string -> convert to dict (dicts are by default sorted) -> convert back to yaml string

def yaml_sort(d):
    try:
        x = yaml.dump(yaml.safe_load(d))
        return x
    except yaml.YAMLError:
        return d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment