def apply(self, strip=0, root=None):
        """ Apply parsed patch, optionally stripping leading components
        from file paths. `root` parameter specifies working dir.
        return True on success
    """
        if root:
            prevdir = os.getcwd()
            os.chdir(root)

        total = len(self.items)
        errors = 0
        if strip:
            # [ ] test strip level exceeds nesting level
            #   [ ] test the same only for selected files
            #     [ ] test if files end up being on the same level
            try:
                strip = int(strip)
            except __HOLE__:
                errors += 1
                warning("error: strip parameter '%s' must be an integer" % strip)
                strip = 0

        # for fileno, filename in enumerate(self.source):
        for i, p in enumerate(self.items):
            if strip:
                debug("stripping %s leading component(s) from:" % strip)
                debug("   %s" % p.source)
                debug("   %s" % p.target)
                old = pathstrip(p.source, strip)
                new = pathstrip(p.target, strip)
            else:
                old, new = p.source, p.target

            filename = self.findfile(old, new)

            if not filename:
                warning("source/target file does not exist:\n  --- %s\n  +++ %s" % (old, new))
                errors += 1
                continue
            if not isfile(filename):
                warning("not a file - %s" % filename)
                errors += 1
                continue

            # [ ] check absolute paths security here
            debug("processing %d/%d:\t %s" % (i + 1, total, filename))

            # validate before patching
            f2fp = open(filename, 'rb')
            hunkno = 0
            hunk = p.hunks[hunkno]
            hunkfind = []
            hunkreplace = []
            validhunks = 0
            canpatch = False
            for lineno, line in enumerate(f2fp):
                if lineno + 1 < hunk.startsrc:
                    continue
                elif lineno + 1 == hunk.startsrc:
                    hunkfind = [x[1:].rstrip(b"\r\n") for x in hunk.text if x[0] in b" -"]
                    hunkreplace = [x[1:].rstrip(b"\r\n") for x in hunk.text if x[0] in b" +"]
                    # pprint(hunkreplace)
                    hunklineno = 0

                    # todo \ No newline at end of file

                # check hunks in source file
                if lineno + 1 < hunk.startsrc + len(hunkfind) - 1:
                    if line.rstrip(b"\r\n") == hunkfind[hunklineno]:
                        hunklineno += 1
                    else:
                        info("file %d/%d:\t %s" % (i + 1, total, filename))
                        info(" hunk no.%d doesn't match source file at line %d" % (hunkno + 1, lineno + 1))
                        info("  expected: %s" % hunkfind[hunklineno])
                        info("  actual  : %s" % line.rstrip(b"\r\n"))
                        # not counting this as error, because file may already be patched.
                        # check if file is already patched is done after the number of
                        # invalid hunks if found
                        # TODO: check hunks against source/target file in one pass
                        #   API - check(stream, srchunks, tgthunks)
                        #           return tuple (srcerrs, tgterrs)

                        # continue to check other hunks for completeness
                        hunkno += 1
                        if hunkno < len(p.hunks):
                            hunk = p.hunks[hunkno]
                            continue
                        else:
                            break

                # check if processed line is the last line
                if lineno + 1 == hunk.startsrc + len(hunkfind) - 1:
                    debug(" hunk no.%d for file %s  -- is ready to be patched" % (hunkno + 1, filename))
                    hunkno += 1
                    validhunks += 1
                    if hunkno < len(p.hunks):
                        hunk = p.hunks[hunkno]
                    else:
                        if validhunks == len(p.hunks):
                            # patch file
                            canpatch = True
                            break
            else:
                if hunkno < len(p.hunks):
                    warning("premature end of source file %s at hunk %d" % (filename, hunkno + 1))
                    errors += 1

            f2fp.close()

            if validhunks < len(p.hunks):
                if self._match_file_hunks(filename, p.hunks):
                    warning("already patched  %s" % filename)
                else:
                    warning("source file is different - %s" % filename)
                    errors += 1
            if canpatch:
                backupname = filename + b".orig"
                if exists(backupname):
                    warning("can't backup original file to %s - aborting" % backupname)
                else:
                    import shutil
                    shutil.move(filename, backupname)
                    if self.write_hunks(backupname, filename, p.hunks):
                        info("successfully patched %d/%d:\t %s" % (i + 1, total, filename))
                        os.unlink(backupname)
                    else:
                        errors += 1
                        warning("error patching file %s" % filename)
                        shutil.copy(filename, filename + ".invalid")
                        warning("invalid version is saved to %s" % filename + ".invalid")
                        # todo: proper rejects
                        shutil.move(backupname, filename)

        if root:
            os.chdir(prevdir)

        # todo: check for premature eof
        return (errors == 0)
dataset/ETHPy150Open ensime/ensime-sublime/patch.py/PatchSet.apply