Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

96 строки
3.7 KiB

# vim: fileencoding=utf-8
#
from .base_format import Format
from calculate.utils.files import Process
from calculate.templates.format.base_format import FormatError
from ..template_engine import ParametersContainer, Variables
from ...variables.datavars import NamespaceNode
from ...variables.loader import Datavars
from typing import Union
from os import path
class PatchFormat(Format):
FORMAT = 'patch'
EXECUTABLE = True
def __init__(self, patch_text: str,
template_path: str,
parameters: ParametersContainer,
datavars: Union[Datavars, NamespaceNode, Variables]):
self._patch_text = patch_text
self._cwd_path = '/'
self._last_level = 0
# Измененные файлы.
self.changed_files = dict()
# Предупреждения.
self._warnings: list = []
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)
@property
def warnings(self):
return self._warnings