Минутка просвещения

Читать в телеге. Когда-то там были посты не только от меня.

Обновление версий библиотек в Gradle

Попадаются задачи, когда надо обновить все версии библиотек в проекте. Руками такое делать в наш век очень уныло.

В Gradle для этого есть несколько плагинов. Основной просто покажет отчет с последними версиями для всех библиотек. Там же есть и ссылки на плагины для автоматического обновления в скрипте билда.

Небольшая проблема в том, что указать версию библиотеки можно кучей разных способов. Простейший — в build.gradle или build.kts. При этом там же ее можно вынести в переменную или в какую-нибудь функцию. Другой способ — каталоги версий, когда версии хранятся в отдельном файле settings.kts или вообще в toml. Разные плагины для автоматического обновления поддерживают разные варианты описания версий — один только в основном скрипте, второй — только в каталогах версий. Первый я попробовал на своем древнем поделии, и там все нормально обновилось (кроме npm, конечно).

Автоматическое обновление имеет минусы. Во-первых, подсовываются иногда beta и RC версии. Во-вторых, breaking changes и вообще списки изменений надо читать самому. Но так-то в проекте все хорошо покрыто тестами и можно не париться, правда же? :)

В Gradle еще есть возможность указать диапазоны версий, например, 1.7.+ — почти как в npm. Но тут я не могу придумать вариант, когда привязка к последней версии лучше, чем воспроизводимая сборка с фиксированными версиями.

СсылкаКомментировать

Список измененных файлов в ветке

Если для какого-нибудь пайплайна надо определить список измененных файлов, то сама команда довольно простая:

git diff-tree --no-commit-id --name-only -r %base_commit_hash% -r %commit_hash%

В качестве %base_commit_hash% и %commit_hash% можно использовать как хэш коммита, так и название ветки (origin/master, например). В CI почти наверняка эти ревизии есть в переменных окружения. В GitLab это CI_MERGE_REQUEST_DIFF_BASE_SHA и CI_COMMIT_SHA.

Однако стоит внимательно следить за этими значениями, если их получаете самостоятельно. Оказывается, нельзя просто так взять и найти коммит, от которого началась ветка. Есть

git merge-base master HEAD 

и эта команда будет неплохо работать в плюс-минус обычных сценариях. Но будет давать неверный результат, если master подмерживается в фиче-ветку.

СсылкаКомментировать

Тьюринг-полнота почти везде

Хорошая статья-сборник про то, какие системы неожиданно или не очень являются Тьюринг-полными.

TLDR: почти любая система с вводом может быть Тьюринг-полной, и легче построить Тьюринг-полную систему, чем неполную. Есть довольно много способов построить простенький вентиль (с помощью поиска и замены, регулярок, разного времени выполнения операций, правил игр и т.д. и т.п.), а там уже и до прочих вычислений недалеко. В каких-нибудь песочницах или компонентах языка программирования (например, в каких-нибудь шаблонах, printf или mov) это вообще элементарно. Все это имеет веселые последствия для ИБ: потенциально в любой “песочнице”, даже сильно зарегулированной, можно исполнять произвольный код, не выходя из нее. А если еще взять во внимания всякие Row hammer и Spectre, то получается, что можно выполнять произвольный код на хосте, не выходя из песочницы. Хотя есть вялая надежда на языки, которые нарочно не Тьюринг-полные, например, тотальное ФП.

СсылкаКомментировать

let и also в Scala

… давно есть. Аналог let — это pipe:

someCollection
  .map(pewpew)
  .pipe(all => if (all.size % 2 == 0) all.drop(1) else all)
  .sum

а замена also — это tap:

someCollection
  .filter(ewew)
  .map(pewpew)
  .flatMap(...)
  .tap(println) // debug
  .reduce(...)

В статье, кстати, они сравниваются с башевскими | и tee, а также с |> из F#. Так что сама идея этих функций далеко не нова, Kotlin их просто сделал более попсовыми.

СсылкаКомментировать

Удаленная работа с docker

С сервисом докера общение идет через сокет, т.е. ничего не мешает с ним общаться по сети, например, через ssh. Простейший вариант — установить переменную окружения DOCKER_HOST как ssh://${USER}@${HOST}. После этого все докер команды будут выполняться на удаленной машине. Можно немного заморочиться и использовать контексты, переключаясь между ними.

Это может быть удобно во всяких скриптах деплоя, например в gitlab-ci. Вместо заворачивания в скрипт или добавления перед каждой командой ssh user@host... просто писать команды и все. Другое преимущество — переменные окружения будут браться локально, а еще локально будут копироваться артефакты через docker cp container:/container/path local/path.

СсылкаКомментировать

Модель акторов для построения бигдаты

А вот и доклад посвежее про Erlang, полуторагодичной давности. В нем кратко объясняется идея акторов и рассказывается о системе учета пациентов, построенной на этой модели. В какой-то момент там внезапно появляются фильтр Блума, рандеву-хеширование, алгоритмы консенсуса и выбора лидера.

Стоит отметить, что система не является основным источником информации (а только для всякой бигдаты), поэтому вопросы того, как делать все транзакционно, тут не поднимаются (впрочем, пациенты довольно изолированы друг от друга, так что это ок, наверно). А так получается практически event sourcing.

СсылкаКомментировать

Модель акторов для построения отказоустойчивой системы

Занятный, хоть и немного старый доклад про проблемы построения отказоустойчивых распределенных систем от автора языка Erlang. Сначала небольшое вступление и полунаглядные примеры, потом на 30 минуте начинается мякоть. Сформулированы 6 правил для потенциального решения проблем:

  1. Изоляция
  2. Конкурентность
  3. Обнаружение ошибок
  4. Понимание, почему они возникли
  5. Обновление кода
  6. Стабильное хранилище

Один из ключевых подходов — “let it crash”. Убийца — дворецкий, Erlang и модель акторов решают все проблемы:)

Я бы посмотрел на этот доклад с двух сторон. Во-первых, со стороны текущих проектов: а как это решается не Erlang’ом? Кубер, телеметрия, helm, postgres, какая-нибудь очередь для доменных событий — вроде уже типовой стек и он почти работает, да? А во-вторых, докладу скоро 10 лет — хорошо ли он состарился?

СсылкаКомментировать

Контракты в Kotlin

Недавно наткнулся на случай, когда они пригодились. Рассмотрим пример:

data class OptionalResult(val data: Payload?, val someFlag: Boolean)

fun OptionalResult?.getData(): Payload {
	this ?: throw NoResultException()
	return this.data ?: throw NoPayloadException()
}

fun someFun(){
	val payload: Payload = getResult().getData()
	doStuffWithPayload(payload)
	if (payload.someFlag){ //oopsie
		// do more stuff 
	}
	...
}

По сути имеем дважды опциональный результат, и в ФП-парадигме это красиво легло бы в мона.. Option, но у нас Kotlin с исключениями. Однако строка с oopsie вызовет ошибку компиляции, т.к. компилятор не понимает, что payload уже был проверен на null. Причем если тело функции подставить вместо вызова, то все будет ок (ссылочная прозрачность плачет в уголочке). Чтобы решить проблему, можно использовать контракты и явно сказать компилятору, что если функция что-то вернула, то ее аргумент — не null:

fun OptionalResult?.getData(): Payload {
	contract {
		returns() implies (this@getData != null)
	}
	this ?: throw NoResultException()
	return this.data ?: throw NoPayloadException()
}

В общем, фича интересная, но, кажется, компилятору стоит быть поумнее.

СсылкаКомментировать

Запуск команды без пароля sudo

Лучше такой пост, чем никакой, наверно :/

  1. Создаем исполняемый скрипт. Его нужно создать через sudo, чтобы нельзя было редактировать. Иначе это будет дырищей, через которую можно будет запускать что угодно.
sudo nano /usr/sbin/some_command
# добавляем shebang и саму команду
# ...
sudo chmod +x /usr/sbin/some_command
  1. Добавляем настройку через sudo visudo, обязательно в конец файла.
some_user ALL=(ALL) NOPASSWD: /usr/sbin/some_command

some_user — имя пользователя.

  1. Теперь можно запускать команду через sudo some_command, и пароль не будет запрашиваться. Можно повесить на хоткей какой-нибудь.

Мне пригодилось для того, чтобы рестартовать демон частоты процессора. Ноут почему-то периодически решает, что 400 MHz хватит всем, почему — быстро не докопался, поэтому решил костылем.

СсылкаКомментировать

Составные шаблоны индексов в Elasticsearch

Оказывается, уже давненько в Elasticsearch можно собрать шаблон индекса по кусочкам, причем их можно переиспользовать — например, какие-нибудь преобразования текста типа стемминга вынести в общий кусочек. Долой копипасту!

СсылкаКомментировать