Здравствуй читатель! Если ты пользователь редактора Emacs, то данная статья для тебя, в ином случае, можно проходить мимо, так как тема достаточно узкоспециализированная.
Меня зовут Вознесенский Михаил. Я руководитель группы разработки продукта RuPost в компании РуПост, которая входит в состав «Группы Астра» (смотри не перепутай ?).
В ходе своей деятельности я сталкивался со множеством текстовых редакторов/IDE и на данный момент остановился на Emacs. Не смотря на всю его мощь, у редактора имеется очень серьёзная проблема, которая мешает нормальной продуктивной деятельности - управление расширениями.
В ходе своего исследования данного вопроса я наткнулся на статью за авторством Божидара Бацова (Bozhidar Batsov). Человек, который называет себя хакером и фанатиком Emacs, но так же является автором конфигурационного фреймворка Prelude.
Статья написана в далёком 2012 году, но остаётся актуальной и по сей день!
Если ты дочитал до этого предложения и тебе всё ещё интересно, то ниже представлен мой перевод с дополнительными комментариями, а активную помощь в редактуре оказал мой коллега Анатолий Гайдай.
Введение
Будем честны — никто не пользуется Emacs без множества расширений ни смотря на то, что Emacs "из коробки" является очень мощным инструментом.
От переводчика: под расширениями в Emacs подразумевают скрипты, которые дают дополнительную функциональность. От альтернативной системы отображения номера строк, как, например, Nlinum, до оконного менеджера на примере проекта exwm.
И управлять этими расширениями, честно говоря, та еще боль в пятой точке. Традиционных подходов к получению расширений для Emacs два. Это установка через пакетный менеджер ОС (если они доступны) или скачивание *.el файлов из различных мест (все ненавидят расширения, распространяемые только через Emacs Wiki и не имеющие репозитория с контролем версий) после прописав их в load-path, и так далее. Более чем очевидно, что такие решения далеки от идеала.
Например, если расширения Emacs были установлены через пакетный менеджер и после этого пришлось поменять ОС (или компьютер) — вы в дерьме. С другой стороны, перенос файлов вручную в .emacs.d эквивалентно департаменту отслеживания версий и зависимостей в аду. Должен быть лучший способ, верно? Было бы замечательно, если бы в Emacs существовал пакетный менеджер, подобно homebrew, apt или yum, не так ли?
Emacs 24 наконец представил такой инструмент — имя его package.el (очень оригинально, да?). Он обещает сделать вашу жизнь чуть проще. Удалось ли выполнить ему своё обещание? Скоро увидим...
Управление пакетами через package.el
package.el идёт в составе Emacs 24, но не является обязательным для Emacs. Перед тем как стать частью Emacs, он был внешним расширением, известным как ELPA (предполагаю, что это означало Emacs Lisp Package Manager, или что-то вроде того). Даже если вы пользователь Emacs 23, то можете скачать последнюю версию package.el с какого-нибудь зеркала Emacs и наслаждаться жизнью. Далее необходимо было сделать что-то вроде этого:
(require 'package)
(package-initialize)
Вставьте этот фрагмент кода где-нибудь в начале вашего конфигурационного файла Emacs — вы определённо захотите, чтобы пакеты, установленные через package.el, были инициализированы раньше, чем вы будете их настраивать.
Что делает package.el на базовом уровне? Устанавливает соединение с репозиториями пакетов, получает список доступных расширений, предоставляет в интерактивном режиме возможность установить пакеты, которые вы хотите (само собой, вы также можете удалить то, что вам не нравится). package.el понимает зависимости между пакетами, и если один пакет нужен для запуска другого, то он будет установлен автоматически, что действительно здорово.
Магия начинается с команды M-x package-list-packages. После её ввода вы должны увидеть что-то вроде этого:
Вы можете двигаться по списку пакетов и помечать клавишей i те, которые хотите установить, или нажать клавишу d для тех, которые хотите удалить. Когда вы закончите, нажмите на x для выполнения запланированных действий.
Изначально package.el не предоставляет возможности для обновления пакета, но это должны исправить в ближайшей сборке Emacs. Согласно почтовой рассылке GNU, вы можете обновить все установленные пакеты, используя клавишу U в буфере списка пакетов (я предполагаю, что строчная u должна обновить только один пакет). К сожалению, в моей сборке отсутствуют эти возможности, поэтому я не могу комментировать их использование.
Вы, наверное, заметили, что ваш список доступных пакетов не особо длинный. Это потому, что официальный репозиторий пакетов в Emacs 24 имеет строгие требования к лицензии (и исходному коду) для того, чтобы включить пакет. К счастью, существует ряд репозиториев, поддерживаемых сообществом вокруг package.el и имеющих менее строгие требования. Наверное, одним из популярнейших является Marmalade, созданный Натаном Вайценбаумом (Nathan Weizenbaum) известный также как Sass and Haml. Вы можете включить его в свой список package-archives примерно так:
(add-to-list 'package-archives
'("marmalade" . "http://marmalade-repo.org/packages/") t)
Marmalade предоставляет веб интерфейсы для загрузки и поиска пакетов (к сожалению, оба глючные) и возможность разделить поддержку пакетов с многими другими людьми, кто будет способен опубликовать новую версию. Там также есть инструмент Emacs Lisp Marmalade, который позволит опубликовать пакет напрямую из Emacs.
Использовать графический интерфейс, предоставляемый package.el — это нормально, если вы обычный пользователь. Но что если у вас есть собственная конфигурация Emacs, хранящаяся в системе управления версиями, которую вы бы хотели мгновенно развернуть на любой ОС/машине (как Emacs Prelude)? Здесь в игру вступает программный интерфейс package.el. При запуске Emacs для автоматической установки (по необходимости) списка необходимых пакетов в Emacs Prelude я использовал следующий код:
(defvar prelude-packages
'(ack-and-a-half auctex clojure-mode coffee-mode deft expand-region
gist groovy-mode haml-mode haskell-mode inf-ruby
magit magithub markdown-mode paredit projectile python
sass-mode rainbow-mode scss-mode solarized-theme
volatile-highlights yaml-mode yari zenburn-theme)
"A list of packages to ensure are installed at launch.")
(defun prelude-packages-installed-p ()
(loop for p in prelude-packages
when (not (package-installed-p p)) do (return nil)
finally (return t)))
(unless (prelude-packages-installed-p)
;; check for new packages (package versions)
(message "%s" "Emacs Prelude is now refreshing its package database...")
(package-refresh-contents)
(message "%s" " done.")
;; install the missing packages
(dolist (p prelude-packages)
(when (not (package-installed-p p))
(package-install p))))
(provide 'prelude-packages)
;;; prelude-packages.el ends here
Этот код проверяет, установлены ли все пакеты из списка, и если хотя бы один не установлен, то обновляет локальную базу данных пакетов (в случае если требуемый пакет недавно добавлен в удалённом репозитории) и устанавливает их.
Для возможности публиковать пакеты в Marmalade, или любом другом репозитории, должна быть стандартизованная структура описания. Пакет из одного файла может выглядеть вот так:
;;; sass-mode.el --- Sass major mode
;; Copyright 2007-2010 Nathan Weizenbaum
;; Author: Nathan Weizenbaum <nex342@gmail.com>
;; URL: http://github.com/nex3/sass-mode
;; Version: 3.0.20
;; Package-Requires: ((haml-mode "3.0.20"))
;; Code goes here
;;; sass-mode.el ends here
Пакет из множества файлов должен иметь дополнительный файл с именем <имя>-pkg.el. Это выглядит примерно так:
(define-package "sass-mode" "3.0.20"
"Sass major mode"
'((haml-mode "3.0.20")))
Плохой, злой
Пока package.el прекрасен на бумаге, но, чтобы заработать по-настоящему, необходимо решить некоторые проблемы.
Обновление должно быть простым
Одно из лучших свойств (или функций) пакетного менеджера ОС в том, что он позволяет действительно легко обновить все установленные пакеты до их последней версии. На текущий момент, package.el не поддерживает этого (по моим сведениям), за исключением клавиши U в представлении списка пакетов. Мне кажется, это довольно базовый функционал и я (а также все, с кем я общался) очень ждут его в финальной версии Emacs 24.
От переводчика: в настоящее время нажатие клавиши U в буфере списка пакетов отметит все пакеты, доступные для обновления, а с помощью клавиши u можно снимать любую ранее установленную отметку для конкретного пакета. Команды для обновления конкретного пакета нет. Вместо этого можно установить доступное обновление пакета (клавиша i) или новый пакет. И наконец можно удалить пакет, нажав клавишу d.
Для применения операций необходимо нажать клавишу x или M-x package-menu-execute. Всё в стиле Emacs. Похожий алгоритм применяется во многих режимах, как например Dired (файловый менеджер).
Слишком многое зависит от Marmalade
Marmalade в последние месяцы стал очень популярным и список его пакетов растёт каждый день. В обычной ситуации это скорее бы порадовало меня, если бы не пару проблем.
Marmalade довольно глючная система (особенно со стороны UI). В ней отсутствует ключевой функционал, как, например, возможность связаться с сопровождающим пакета. Было время, когда даже отсутствовала возможность удалить пакет. Загрузка работает не надёжно. Обновление пакетов иногда возвращает HTTP-ошибки, которые
требуют ручного обновления M-x package-refresh-contents, и время от времени сервис бывает недоступен.
Похоже проекту не уделяется большое внимание со стороны внутренней поддержки (что вполне объяснимо, учитывая факт сопровождения автором некоторых серьёзных проектов + полная ставка в Google).
Следствием этого является то, что backend написан на Node.js (прекрасная технология, но сейчас не широко распространена) и размещён на Google Code - что не очень улучшает ситуацию. Решение на основе Ruby или Python, размещённое на GitHub, однозначно, получило бы большую популярность в сообществе (и я планирую начать работу на одном из них в ближайшее время).
От переводчика: а теперь внимание, Marmalade мёртв. Проект перестал существовать в 2021 году. Теперь на его месте проект MELPA.
Скудная документация
В package.el поверхностная документация и вам придётся изучать исходный код, если вы захотите реализовать требуемый интерфейс (который, к счастью, очень простой).
Я надеюсь, что это изменится на релизе Emacs 24.
От переводчика: Emacs в целом имеет достаточно подробную документацию:
Режим работы с пакетами описан в 49 главе.
О том, как подготовить пакет к дистрибуции, описано в 43 главе.
Как настраивать пакеты в конфигурационном файле доступно в отдельной документации use-package.
Слишком мало авторов пакетов заботит package.el
Авторы пакетов редко помечают версии того, что можно загрузить в совместимый репозиторий package.el, и время от времени не соблюдают требуемую базовую структуру. Я всегда связываюсь с авторами пакетов, чтобы сообщить им о таких недостатках, и вы должны делать так же.
От переводчика: ничего не поменялось. В официальном репозитории, доступном через package.el "из коробки", до сих пор очень мало пакетов.
Альтернативы
el-get - другое известное решение по управлению расширениями в Emacs, которое в недавнее время стало популярным.
el-get позволяет вам устанавливать для Emacs elisp-скрипты и управлять ими. Он поддерживает множество типов источников (git, svn, apt, elpa, и т.д.) и умеет устанавливать, обновлять и удалять их. Но, что более важно, он запустит их за вас.
Это означает, что будут выполнены следующие действия:
загрузка необходимых файлов;
определение путей таким образом, чтобы C-h i показывала новую документацию, от которой вы теперь зависимы;
вызов своей функции :post-init для настройки расширений.
Проще говоря, обернёт это всё пакетом.
el-get, по сути, проблемный кусок программного обеспечения на Windows-машинах и изначально был разработан, чтобы без лишних сложностей получать пакеты последней версии из git. Хотя некоторые считают его неплохим дополнением к package.el,
я чувствую, что el-get слишком низкоуровневый инструмент (в своём подходе к проблеме) и его следует избегать.
Касательно git — ветка master-пакета часто имеет ошибки. Также есть авторы, которые никогда не ставят тег версии и полагаются на модель "плавающий релиз" (rolling release). Такая практика мне крайне не нравится и я всецело поддерживаю выпуск стабильных версий.
Обновление
Через несколько часов после публикации этой статьи я получил объёмный комментарий от автора el-get. Поскольку я считаю, что данный комментарий весьма интересный, я привожу его ниже без каких-либо изменений:
Это автор el-get, хорошая статья! Ситуация с Emacs расширениями далека от идеала и требует жёсткой критики, чтобы была проведена работа по её улучшению.
А теперь я хочу поделится с тобой парой особенностей, которые сейчас доступны только в ветке разработчиков el-get (скоро станут доступны - с выходом 4.1): теперь можно легко переключиться на стабильную ветку в git репозитории (спасибо свойствам :checkout) и теперь вы можете даже настроить контрольную сумму того, что хотите установить.
Итак, если вы используете git, то контрольная сумма (уникальный идентификатор) является конкретной версией. Например, когда используется emacswiki, вы должны вычислить контрольные суммы (выполнить M-x el-get checksum) и зарегистрировать их в своём
el-get-sources. Тогда, если файл будет изменён на emacswiki, то el-get откажется его загружать (надеюсь, до тех пор пока вы не закончите с рецензией и после обновите контрольную сумму).Следовательно, несмотря на то, что я понимаю ваше нежелание зависеть от el-get, я верю, что ваши опасения сейчас развеяны. Мне хотелось бы верить, что авторы сценариев на Emacs Lisp найдут время, чтобы обсудить их подходы в исходниках для package.el.
Сегодня это не так-то просто, так что, выбирая ELPA, вы много чего лишаетесь. И для изменения ситуации вам нужны авторы, готовые упаковывать свои расширения - или же вам придётся делать форк их работ. С el-get вы получаете доступ к 536 пакетам c самого начала, и всё с emacswiki (на текущий момент более 1700 пакетов) - после того как вы выполните M-x el-get-emacswiki-refresh. На момент написания этого комментария, команда M-x el-get-package-list мне показала 2106 пакетов, готовых к установке, и почти все имеют описание. el-get - это "социальное опакечивание", где легко подготовить рецепт для пакета вне зависимости от способа дистрибуции, выбранного автором.
Затем вы можете очень легко поделится своим рецептом, например, с el-get на github, где мы будем очень рады принять вашу работу и установить её по умолчанию, когда пользователь установит el-get, или сделает M-x el-get-self-update.
Что касается Windows-поддержки, то всё зависит от пакетов, которые вы хотите установить. Большинство из них просто работают "из коробки", являясь одним файлом (.el) на Emacs Lisp. Некоторые из них требуют установки дополнительных инструментов, от git, svn, или mercurial, до make или autoconf. Вне зависимости от того, как авторы предоставляют свои расширения, el-get всего лишь даёт нативный способ их получения. Мы сделали ряд улучшений, чтобы пользовательский опыт на других ОС совпадал с Windows, так как мы считаем эту платформу наиболее развитой.- Дмитрий Фонтейн (Dimitri Fontaine), автор el-get
Эпилог
package.el — это будущее управления пакетами в Emacs. Я в этом совершенно уверен. Он далёк от совершенства, но даже в таком ущербном виде, он уже весьма упростил жизнь многим Emacs-пользователям. Я призываю всех вас прекратить публиковать Emacs-пакеты через исходники, как, например, Emacs Wiki, а уделять пристальное внимание package.el. Сделайте ваши пакеты совместимыми с ним, публикуйте в репозиториях, поддерживаемых сообществом (или в официальные по возможности) и держите их актуальными. Пользователи будут благодарны вам за это!
Я также хотел бы увидеть замену Marmalade в будущем. Более зрелое и отполированное решение, поддерживаемое командой из множества людей. Надеюсь, этот момент настанет в недалёком будущем.
От переводчика
К сожалению, спустя более 10 лет с момента публикации оригинальной статьи ничего кардинально не изменилось. Безусловно, есть изменения в положительную сторону, но основные проблемы как были, так и остаются:
Чтобы пользоваться package.el, необходимо как минимум подключить репозитории MELPA и ELPA, так как очень многое недоступно "из коробки".
Пакеты из сторонних репозиториев не имеют должного сопровождения.Это означает, что после обновление пакета, он легко может перестать работать, при этом откатить установленное расширение нельзя. Даже после фиксирования проблемы на стороне разработчиков, пакет никто не будет откатывать - жди обновлений, или делай всё руками.
Тегирование пакетов не прижилось в сообществе. Уникальные идентификаторы победили.Не сказать, что это сильно как-то повлияло, но оперировать SHA1 в разработке, мягко говоря, не очень удобно. Ранее упомянутый проект Prelude (автора оригинальной статьи) перестал тегироваться и обновлять документацию.
На сегодняшний момент существуют ряд проектов, способных помочь исправить эту проблему:
Все они представляют альтернативу package.el и имеют ключевой функционал — фиксирование версий расширений.
Также стоит упомянуть про package-vc-install, который появился в Emacs 29.1. С его помощью можно зафиксировать версию расширения, но это больше инструмент для разработки: "This often makes it easier to develop patches and report bugs."
Сам Божидар Бацов (Bozhidar Batsov), спустя столько времени и явных проблем, не переходит на альтернативные пакетные менеджеры в проекте Prelude, объясняя это тем, что package.el является стандартом в сообществе. Как и в 2012 году, так и в 2024 он верит, что в будущем ситуация изменится.