"""
Docker layer size report

    python docker_layer_sizes.py <image>

Returns the size of each layer of the image and the command that created it.

This is a decorative layer on top of the docker history command.
"""

import subprocess
import sys
import re
from pygments import highlight
from pygments.styles import get_style_by_name
from pygments.lexers import DockerLexer
from pygments.formatters import Terminal256Formatter

INDENT = 8
LEXER = DockerLexer()
FORMATTER = Terminal256Formatter(style=get_style_by_name("rrt"))
MULTISPACE = re.compile(r" {2,}")
NOP_PREFIX = re.compile(r".*#\(nop\) +", re.DOTALL)


class Command:
    shell = ""

    def __init__(self, string):
        self.size, self.instr = string.split("\t", 1)
        if self.size == "0B":
            self.size = ""

        if self.cmd == "SHELL":
            self.__class__.shell = self.text[1:-1]

    @property
    def cmd(self):
        return self.instr.split(" ", 1)[0]

    @property
    def text(self):
        return self.instr.split(" ", 1)[1]

    def __repr__(self):
        instr = re.sub(NOP_PREFIX, "", self.instr)
        instr = re.sub(MULTISPACE, " ", instr)

        if self.cmd != "SHELL":
            instr = instr.replace(f"RUN {self.__class__.shell}", "RUN")
            instr = instr.replace(self.__class__.shell, "RUN")

        instr = instr.replace(" RUN", "\n" + " " * (INDENT + 3))

        instr = highlight(instr, LEXER, FORMATTER).strip()

        instr = [x.strip() for x in instr.split("&&")]
        instr = f"\n{'':>12}&&".join(instr)

        return f"{self.size:>6}  {instr}"


def data(image) -> str:
    """Ask docker for our data."""

    proc = subprocess.run(
        [
            "docker",
            "history",
            "--no-trunc",
            "--format",
            "{{.Size}}\t{{.CreatedBy}}",
            image,
        ],
        check=True,
        capture_output=True,
    )

    return [Command(line) for line in proc.stdout.decode("utf-8").strip().split("\n")][
        ::-1
    ]


def main(image):
    """Run the program."""

    output = data(image)

    for line in output:
        print(line)


if __name__ == "__main__":
    main(sys.argv[1])