03.14 Git и оформление патчей в виде файлов
- Как передавать изменения, если доступна только голубиная почта?
- пересылать можно только файлы
- git push/pull недоступны
Задача_1: сформируйте патчсет и наложите его на другую ветку.
- Создание истории изменений:
- Ниже приведен стишок из 20 строк. Считаем, что они пронумерованы с 1 по 20 (номера строк в стишок не входят).
- Создайте в репозитории ветку "master_20220314" и работайте на ней.
- Создайте и закоммитьте текстовый файл "opilki.txt" с нижеприведённым стишком.
- Выберите три разных номера строк по следующей схеме: рассчитайте сумму MD5 от ваших фамилии, имени, отчества (по отдельности), от каждого полученного числа возьмите остаток от деления на 20 и добавьте 1. Если два числа совпали, увеличьте (или уменьшите) одно из них на 5 (или на 7).
python3 -c 'import hashlib; print(hashlib.md5("Фамилия".encode()).digest()[0]%20+1)'
- Для каждой из трёх строк с полученными номерами:
- Измените эту строку, но так, чтобы текст оставался рифмованным (если нет склонности к стихосложению, просто перепишите строку заглавными буквами).
Сделайте отдельный коммит с изменением в этой строке, назовите его "Правка строки <номер_строки>".
- Проверка: к этому моменту на ветке "master_20220314" должна быть история из четырёх коммитов: первоначальное занесение файла и три коммита с однострочными правками.
- Создание патчсета:
- Создайте подкаталог "patchdir".
При помощи команды git format-patch с ключом --output-directory создайте в подкаталоге "patchdir" патчсет из трёх последних коммитов (т.е. не включая первоначальное занесение файла).
- ПОКАЖИТЕ ПАТЧСЕТ ВЕДУЩИМ ПРАКТИКУМА
- Применение патчсета:
- Создайте ветку "check_20220314" от коммита с первоначальным занесением файла "opilki.txt" и работайте на этой ветке.
При помощи команды git am patchdir примените патчсет.
- Проверка: на ветке "check_20220314" должна возникнуть история из трёх однострочных изменений.
push нужно сделать для обеих созданных веток; patchdir коммитить не надо
- Стишок из 20 строк:
- Создание истории изменений:
1 Опять ничего не могу я понять.
2 Опилки мои – в беспорядке.
3 Везде и повсюду, опять и опять
4 Меня окружают загадки.
5 Возьмём это самое слово "опять".
6 Зачем мы его произносим,
7 Когда мы свободно могли бы сказать
8 "Ошесть", и "осемь", и "овосемь"?
9 Молчит этажерка, молчит и тахта –
10 У них не добьёшься ответа,
11 Зачем это хта – обязательно та,
12 А жерка, как правило, эта!
13 "Собака кусается"... Что ж, не беда.
14 Загадочно то, что собака,
15 Хотя и кусается, но никогда
16 Себя не кусает, однако...
17 О, если бы мог я всё это понять.
18 Опилки пришли бы в порядок!
19 А то мне – загадочно! – хочется спать
20 От всех этих Трудных Загадок!
Работа с исходным текстом. ast (На лекциях были inspect и dis, но на всё времени не хватит.).
- Что и зачем нужен
ast.parse(), ast.dump() и ast.unparse()
написать простейшую утилиту purify.py программа.py, которая удаляет комментарии и переформатирует программу.py, выводя результат на экран
К. О. спешит на помощь: unparse(parse())
Представление (примитивное) о структуре AST. walk()
Работа с исходным текстом. difflib
- виды diff
Использование Tools/scripts/diff.py
переназвать предыдущую программу в diffpure.py и модифицировать так, чтобы выводилcя unified_diff() исходного файла и его и «purify-фированного» варианта
Задача_2. Антиплагиат. Написать программу antip.py файл_1.py файл_2.py, которая получает на вход два (сравнительно небольших) файла на python, и делает с ними следующее.
Получает для исходного текста в каждом файле «унифицированное представление» с помощью ast.unpasre(ast.parse())
- Преобразует AST-дерево разбора каждого файла в т. н. «препарат» с целью минимизировать его представление (с потерей восстановимости)
Вариант решения: взять ast.dump(текст, annotate_fields=False) и крепко пожевать его regexp-ами или просто replace()-ами
Вариант решения: посмотреть, как ast.dump() обходит дерево и енаписать свой примитивный обходчик, который оставляет только нужную информацию
Вариант решения «по-врослому»: воспользоваться ast.NodeVisitor
- Я воспользовался вариантом 1:
Выдрал из ast.dump() только идентификаторы, начинающиеся с большой буквы, после которых стоит открывающая скобка (это лексические конструкции, см грамматику в начале документации по ast), запятые (это количество элементов в конструкции) и закрывающие скобки (они указывают контекст).
В полученных препаратах заменил каждый «Идентификатор(» уникальным одним символом.
Вычисляет нормализованное расстояние Дамерау-Левенштейна между двумя препаратами (textdistance.damerau_levenshtein.normalized_distance)
Если это расстояние не превышает 0.1, сообщает о возможном плагиате, в доказательство чего выводит difflib.HtmlDiff() между унифицированными представлениями программ (в них одинаковое форматирование и опущены комментарии).
Два файла в примере из Д/З по лекциям должны распознаваться как 100% совпадающий.
TODO пример не 100% совпадения