[О блоге]
[наверх]
[пред]
[2020-11-20 19:40:50+03:00]
[fbfbf62ce9cb0a3fcb97e02d6fc05c249bb4e162]
Темы: [go][redo]
I redo redo
http://git.cypherpunks.ru/cgit.cgi/goredo.git/tree/README
Психанул и написал свою redo реализацию на Go!
Python apenwarr/redo всем хорош, но Python зависимость не очень приятна.
Плюс при большом уровне параллелизма у него иногда что-то сбоит и он
падает. Не критично, ибо всё равно потом всё недособранное можно
пересобрать (это ж не Make, где с чистого листа только безопасно будет),
но не приятно.
redo-c не имеет redo-stamp команды. С ней просто приятнее и удобнее
жить. Плюс он не уважает umask, ибо просто используется mkstemp(). И
мозолят глаза его .dep. файлы в каждой директории.
Решил было просто переписать его на Go. И в основу он полностью и лёг.
Но на Go так приятно и легко пишется, что я по сути почти все фичи
apenwarr/redo реализации засунул. Ровно один день чтобы написать рабочую
(текущие проекты полностью мочь без проблем *пере*собирать) redo
реализацию. Тестами ничего не покрыто, но у себя всё что в голову
приходило и на нетривиальном проекте с default/redo-stamp разнообразием
оно отрабатывает идеально. Сейчас я даже Python реализацию удалил из
путей.
Что добавил, чего не было в redo-c:
* всегда захватывать stdout. Как и в apenwarr/redo, явно проверяется не
записал ли пользователь И в stdout И в $3. Я не раз по неосторожности
так делал и это сильно помогало
* явно проверять что собранный файл не изменился пользователем, вне
контекста сборки redo, опять же, как это делает apenwarr/redo -- это
очень удобно, ибо позволяет временно вносить правки и смотреть что
получится, но файлы не будут перезатёрты
* исполняемые файлы запускаются как есть, содержащие shebang --
запускаются с ним. Ну а оставшиеся с /bin/sh -e (или -x в дополнении)
* redo -x покажет trace (sh -x) только для текущих указанных целей, а не
всех -- оказалось это очень удобно (но можно через env выставить и
показ вообще всего для всех)
* уважение umask
* redo-stamp, redo-whichdo (мне не надо, но сделать легко)
* в .dep файле сохраняется и UUID сборки, по которому можно понять а
была ли цель уже собрана, ведь от неё могут зависеть многие, а на ней
стоит redo-always или redo-stamp какой-нибудь. Позволяет избежать
возможных повторных ненужных сборок. В apenwarr/redo тоже хранится
информация о конкретной сборки, поэтому в нём тоже избежали эту
проблему
* lock-и и зависимости для каждой цели у меня аналогично в отдельных
файлах, но все они собраны в .redo поддиректории (каждой директории
проекта), что просто разгружает глаз. Там же хранятся и .log файлы
А теперь отличия от навороченного apenwarr/redo:
* apenwarr/redo проверяет размеры, mtime и ещё несколько параметров
файла для определения его свежести. Насколько понимаю, ctime он не
использует потому что он меняется с изменением link count-а. Я
использовал подход redo-c: проверка ctime, если не совпал, то проверка
хэша файла. Проверка хэша убирает false positive срабатывание. Если
хочется иметь "вечную" цель, то, как и redo-c, как и apenwarr/redo,
отсутствие файла воспринимают как тухлость. Последние правки в redo-c
не удаляют файл, если stdout был пуст -- это ломает подобный подход. Я
поэтому делал revert коммита. Ибо это добавляет гибкости и отсутствие
проблем из-за хэширования пустоты. В итоге имеем и гибкость и false
positive защиту хэшом. Если покажется кому-то медленным, то добавил
возможность отключения хэширования (как apenwarr/redo будет). Для хэша
использую BLAKE2b
* я явно делаю sync для созданных целей и файлов зависимостей, а также
директорий после переименования файлов. Можно отключить. apenwarr/redo
не делает sync ни для целей, ни для SQLite3 БД, явно отключая
синхронность
* распараллеливание работы делается через jobserver-like протокол, но с
возможностью infinite работ. У меня на C проекте это позволяет сверх
быстро собрать его
* у меня разукрашенный вывод, с удобными indent-ами, возможностью показа
когда цель завершена и сколько это заняло времени, возможностью
показа PID-ов. stderr задач можно тоже показывать с PID-ом самого
shell-скрипта выполняющегося. У меня сверх verbose debug вывод, весь
из себя разукрашенный, показывающий все принимаемые решения и шаги
* stderr каждой цели можно сохранить на диск автоматом, но в нём каждая
строка будет ещё и с TAI64N timestamp-ом, совместимым с tai64nlocal
утилитой. redo-log команда позволит просмотреть его
* состояние хранится в .dep файлах которые являются recfile-ами
(8249370437018ad186c7946f22242731fba52035, d47bdefa40f41b81435565029c035f62614fe0da)
Особо надобности в этом нет, oneline формат redo-c не проблематичен,
но так красивее, мне кажется
* в процессе работы создаются временные файлы, которые при убийстве
процесса не подчищаются. Сделал отдельную redo-cleanup команду для их
подчистки и возможности вообще удаления .redo отовсюду, для начала с
чистого листа
* apenwarr/redo даже в FAQ говорит что скорее всего начнёт создавать
.redo поддиректории в каждой директории, ибо не понятно как выяснять
что является верхним уровнем проекта. Я сделал подход redo-c: вплоть
до корня ФС он будет искать .do файлы. Но, с возможностью ограничения
"сверху" через REDO_TOP_DIR переменную или наличию .redo/top файла.
И оптимизация и безопасность если проект и подпроект используют redo,
но должны быть независимы друг от друга. Насколько понимаю,
apenwarr/redo тут будет иметь проблемы
Наконец, goredo имеет "gore" корень, что не может меня, любителя
goregrind, не радовать. Это один исполняемый файл, на который нужно
создать символические ссылки. Точнее запустить с -symlinks опцией, чтобы
он это сделал сам.
goredo в итоге работает и собирает проект даже на глаз ОЩУТИМО быстрее.
Всё же, как ни крути, но Python это Python и быстро запуститься
программа на нём не может. Чтобы просто перезапустить rebuild, который
пройдёт по целям делающим redo-stamp, apenwarr/redo нужно время заметное
на глаз, тогда как goredo отрабатывает вмиг. В общем, пока для меня это
идеальная redo реализация!
Смотрел ли я ещё на какие-нибудь?
* Haskell реализация поддерживает только redo-ifchange. Да, это основное
и главное, но нет, хочется большего
* Есть 2-3 реализации на shell (не считая работающего apenwarr/do, но не
делающего rebuild), но либо они требуют либо GNU утилит, либо вообще
bash (идёт сразу в жопу)
* redux на Go я даже пробовал запускать. Он создавал какое-то дичайшее
количество (многие мегабайты) JSON файлов, но .do вроде запускал.
Только с безумно низкой скоростью это всё работало и я даже через
десятки секунд (минуты?) не дождался конца и нажал Ctrl-C. Просто
неюзабельно
* C++ не смотрел, ибо нафиг этот язык, тем более для выполнения redo задачи
* Отпадают не совместимые с redo(-ifchange) реализации
И только с написанием goredo я наконец-то понял надобность в
redo-ifcreate! Например есть цель "foo", но нет "foo.do", а есть
"default.do" (где-нибудь). Если в зависимости будет прописано только
"foo" и "default.do", то появление "foo.do" не заставить цель протухнуть!
Поэтому пути поиска default.do файлов автоматически прописываются в
зависимости, как-будто был вызван redo-ifcreate. Очень красиво, на мой
взгляд. Как пользователь, я redo-ifcreate так и не знаю где вызвать, но
внутри без него вижу что нельзя. Ведь и зависимость от .do файла явно
никто не прописывает -- оно автоматически.
[оставить комментарий]
- комментарий 0:
From: kmeaw
Date: 2020-12-02 16:08:53Z
Похоже, то ли что-то случилось со ссылкой, то ли cgit обновился, но я
получаю 404. Вот работающая ссылка:
http://git.cypherpunks.ru/?p=goredo.git;a=blob;f=README;h=1c9e59be4026be59a0999487ff49602a700fd5da;hb=HEAD
- комментарий 1:
From: Sergey Matveev
Date: 2020-12-02 16:11:29Z
*** kmeaw [2020-12-02 19:03]:
>Похоже, то ли что-то случилось со ссылкой, то ли cgit обновился
Я буквально сегодня заменил cgit на gitweb, который из коробки с git-ом
идёт. Всё равно находится в системе да и проще его собирать. Сейчас
более корректная ссылка это http://www.goredo.cypherpunks.ru/