|
|
|
|
# vim: fileencoding=utf-8
|
|
|
|
|
#
|
|
|
|
|
from .base_format import Format
|
|
|
|
|
from calculate.utils.files import Process
|
|
|
|
|
from calculate.templates.format.base_format import FormatError
|
|
|
|
|
from os import path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PatchFormat(Format):
|
|
|
|
|
FORMAT = 'patch'
|
|
|
|
|
EXECUTABLE = True
|
|
|
|
|
|
|
|
|
|
def __init__(self, patch_text: str,
|
|
|
|
|
template_path: str,
|
|
|
|
|
ignore_comments=None):
|
|
|
|
|
self._patch_text = patch_text
|
|
|
|
|
self._cwd_path = '/'
|
|
|
|
|
self._last_level = 0
|
|
|
|
|
|
|
|
|
|
# Измененные файлы.
|
|
|
|
|
self.changed_files = dict()
|
|
|
|
|
|
|
|
|
|
def execute_format(self, target_path, chroot_path='/'):
|
|
|
|
|
'''Метод для запуска работы формата.'''
|
|
|
|
|
self._cwd_path = target_path
|
|
|
|
|
if not path.isdir(self._cwd_path):
|
|
|
|
|
# Если target_path -- путь к файлу, запускаем все процессы из
|
|
|
|
|
# директории, в которой этот файл находится.
|
|
|
|
|
self._cwd_path = path.dirname(self._cwd_path)
|
|
|
|
|
|
|
|
|
|
if not path.exists(self._cwd_path):
|
|
|
|
|
raise FormatError('root path does not exist', executable=True)
|
|
|
|
|
|
|
|
|
|
if self._patch_text:
|
|
|
|
|
self._patch_document()
|
|
|
|
|
return self.changed_files
|
|
|
|
|
else:
|
|
|
|
|
raise FormatError('empty patch file', executable=True)
|
|
|
|
|
|
|
|
|
|
def _patch_document(self):
|
|
|
|
|
'''Метод, производящий наложение патча путем запуска процесса patch.'''
|
|
|
|
|
# Сначала определяем на каком уровне накладываем патч.
|
|
|
|
|
# Для этого запускаем утилиту patch с --dry-run и смотрим результат
|
|
|
|
|
# выполнения.
|
|
|
|
|
for level in range(0, 4):
|
|
|
|
|
patch_dry_run = Process('patch', '--dry-run',
|
|
|
|
|
'-p{}'.format(level),
|
|
|
|
|
cwd=self._cwd_path)
|
|
|
|
|
patch_dry_run.write(self._patch_text)
|
|
|
|
|
if patch_dry_run.success():
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
patch_dry_run = Process('patch', '-R', '--dry-run',
|
|
|
|
|
'-p{}'.format(level),
|
|
|
|
|
cwd=self._cwd_path)
|
|
|
|
|
patch_dry_run.write(self._patch_text)
|
|
|
|
|
if patch_dry_run.success():
|
|
|
|
|
return ''
|
|
|
|
|
else:
|
|
|
|
|
raise FormatError('correction failed', executable=True)
|
|
|
|
|
|
|
|
|
|
self._last_level = level
|
|
|
|
|
patch_run = Process('patch', '-p{}'.format(level),
|
|
|
|
|
cwd=self._cwd_path)
|
|
|
|
|
patch_run.write(self._patch_text)
|
|
|
|
|
|
|
|
|
|
if patch_run.success():
|
|
|
|
|
for line in patch_run.read_lines():
|
|
|
|
|
if line.startswith('patching file'):
|
|
|
|
|
changed_file_path = path.join(self._cwd_path,
|
|
|
|
|
line[13:].strip())
|
|
|
|
|
if path.exists(changed_file_path):
|
|
|
|
|
self.changed_files.update({changed_file_path:
|
|
|
|
|
'C'})
|
|
|
|
|
else:
|
|
|
|
|
self.changed_files.update({changed_file_path:
|
|
|
|
|
'D'})
|
|
|
|
|
return patch_run.read()
|
|
|
|
|
else:
|
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
|
def __bool__(self):
|
|
|
|
|
return bool(self._patch_text)
|