"""
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)

[((24, 27, 24, 59), 'os.path.join', 'path.join', ({(24, 37, 24, 47): 'xdelta_dir', (24, 49, 24, 58): '"""xdelta3"""'}, {}), "(xdelta_dir, 'xdelta3')", False, 'from os import remove, path\n'), ((39, 8, 39, 25), 'logging.info', 'logging.info', ({(39, 21, 39, 24): 'cmd'}, {}), '(cmd)', False, 'import logging\n'), ((60, 8, 60, 25), 'logging.info', 'logging.info', ({(60, 21, 60, 24): 'cmd'}, {}), '(cmd)', False, 'import logging\n'), ((41, 12, 41, 29), 'subprocess.check_output', 'check_output', ({(41, 25, 41, 28): 'cmd'}, {}), '(cmd)', False, 'from subprocess import check_output, CalledProcessError\n'), ((47, 12, 47, 60), 'shutil.copyfile', 'copyfile', ({(47, 21, 47, 34): 'self.original', (47, 36, 47, 59): "(self.original + '_temp')"}, {}), "(self.original, self.original + '_temp')", False, 'from shutil import copyfile\n'), ((62, 12, 62, 29), 'subprocess.check_output', 'check_output', ({(62, 25, 62, 28): 'cmd'}, {}), '(cmd)', False, 'from subprocess import check_output, CalledProcessError\n'), ((67, 16, 67, 37), 'os.remove', 'remove', ({(67, 23, 67, 36): 'self.original'}, {}), '(self.original)', False, 'from os import remove, path\n')]