"""
Utils for creating xdelta patches.
"""
import logging
from subprocess import check_output, CalledProcessError
from shutil import copyfile
from os import remove, path


class PatchChecksumError(Exception):
    def __init__(self, message, errors):
        super(PatchChecksumError, self).__init__(message)


class Patch:
    # TODO: Abstract out the need for "edited" by just copying the original
    # file.
    def __init__(self, original, filename, edited=None, xdelta_dir='.'):
        self.original = original
        self.edited = edited
        self.filename = filename

        # Need to have this absolute path for xdelta3 to be found.
        self.xdelta_path = path.join(xdelta_dir, 'xdelta3')
        # self.xdelta_path = 'xdelta3'

    def create(self):
        if self.edited is None:
            raise Exception
        cmd = [
            self.xdelta_path,
            '-f',
            '-s',
            self.original,
            self.edited,
            self.filename,
        ]
        print(cmd)
        logging.info(cmd)
        try:
            check_output(cmd)
        except CalledProcessError as e:
            raise Exception(e.output)

    def apply(self):
        if not self.edited:
            copyfile(self.original, self.original + "_temp")
            self.edited = self.original
            self.original = self.original + "_temp"
        cmd = [
            self.xdelta_path,
            '-f',
            '-d',
            '-s',
            self.original,
            self.filename,
            self.edited,
        ]

        logging.info(cmd)
        try:
            check_output(cmd)
        except CalledProcessError:
            raise PatchChecksumError('Target file had incorrect checksum', [])
        finally:
            if self.original.endswith('_temp'):
                remove(self.original)

[((674, 706), 'os.path.join', 'path.join', (['xdelta_dir', '"""xdelta3"""'], {}), "(xdelta_dir, 'xdelta3')\n", (683, 706), False, 'from os import remove, path\n'), ((1027, 1044), 'logging.info', 'logging.info', (['cmd'], {}), '(cmd)\n', (1039, 1044), False, 'import logging\n'), ((1567, 1584), 'logging.info', 'logging.info', (['cmd'], {}), '(cmd)\n', (1579, 1584), False, 'import logging\n'), ((1070, 1087), 'subprocess.check_output', 'check_output', (['cmd'], {}), '(cmd)\n', (1082, 1087), False, 'from subprocess import check_output, CalledProcessError\n'), ((1228, 1276), 'shutil.copyfile', 'copyfile', (['self.original', "(self.original + '_temp')"], {}), "(self.original, self.original + '_temp')\n", (1236, 1276), False, 'from shutil import copyfile\n'), ((1610, 1627), 'subprocess.check_output', 'check_output', (['cmd'], {}), '(cmd)\n', (1622, 1627), False, 'from subprocess import check_output, CalledProcessError\n'), ((1823, 1844), 'os.remove', 'remove', (['self.original'], {}), '(self.original)\n', (1829, 1844), False, 'from os import remove, path\n')]