Пакеты
В Julia есть встроенный менеджер пакетов для установки дополнительного функционала, написанного на Julia. Он также может устанавливать внешние библиотеки, используя стандартную систему вашей операционной системы для этого или компилируя их из исходного кода. Список зарегистрированных пакетов Julia можно найти по адресу http://pkg.julialang.org. Все команды менеджера пакетов находятся в модуле Pkg, включенном в установку Julia Base.
Сначала мы рассмотрим механику команд семейства Pkg и затем дадим некоторые рекомендации по регистрации вашего пакета. Не забудьте прочитать раздел ниже о соглашениях об именовании пакетов, маркировке версий и важности файла REQUIRE, когда вы готовы добавить свой код в хранилище METADATA.
Статус пакета
Функция Pkg.status() выводит сводку состояния установленных пакетов. Изначально у вас нет установленных пакетов:
julia> Pkg.status() INFO: Initializing package repository /Users/stefan/.julia/v0.5 INFO: Cloning METADATA from git://github.com/JuliaLang/METADATA.jl No packages installed.
Ваш каталог пакетов автоматически инициализируется при первом запуске команды Pkg, которая ожидает его существования — это включает в себя команду Pkg.status(). Вот пример нетривиального набора необходимых и дополнительных пакетов:
julia> Pkg.status() Required packages: - Distributions 0.2.8 - UTF16 0.2.0 Additional packages: - NumericExtensions 0.2.17 - Stats 0.2.6
Все эти пакеты находятся на зарегистрированных версиях, управляемых Pkg. Пакеты могут находиться в более сложных состояниях, указанных аннотациями справа от установленной версии пакета; мы объясним эти состояния и аннотации по мере их появления. Для программирования, Pkg.installed() возвращает словарь, сопоставляющий имена установленных пакетов с установленной версией этого пакета:
julia> Pkg.installed()
Dict{String,VersionNumber} with 4 entries:
"Distributions" => v"0.2.8"
"Stats" => v"0.2.6"
"UTF16" => v"0.2.0"
"NumericExtensions" => v"0.2.17"
Добавление и удаление пакетов
Менеджер пакетов Julia немного необычен тем, что он декларативный, а не императивный. Это означает, что вы указываете, что хотите, а он определяет, какие версии установить (или удалить), чтобы оптимально и минимально удовлетворить эти требования. Таким образом, вместо установки пакета вы просто добавляете его в список требований, а затем «разрешаете» установку необходимого. В частности, это означает, что если какой-то пакет был установлен, потому что он был необходим предыдущей версией того, что вы хотели, а более новая версия больше этого не требует, обновление фактически удалит этот пакет.
Ваши требования к пакетам находятся в файле ~/.julia/v0.5/REQUIRE. Вы можете отредактировать этот файл вручную, а затем вызвать Pkg.resolve() для установки, обновления или удаления пакетов для оптимального удовлетворения требований, или вы можете выполнить Pkg.edit(), которое откроет REQUIRE в вашем редакторе (настроенном через переменные окружения EDITOR или VISUAL) и затем автоматически вызовет Pkg.resolve(), если это необходимо. Если вы хотите добавить или удалить требования только для одного пакета, вы также можете использовать неинтерактивные команды Pkg.add() и Pkg.rm(), которые добавляют или удаляют одно требование к REQUIRE и затем вызывают Pkg.resolve().
Вы можете добавить пакет в список требований с помощью функции Pkg.add(), и пакет, а также все пакеты, от которых он зависит, будут установлены:
julia> Pkg.status()
No packages installed.
julia> Pkg.add("Distributions")
INFO: Cloning cache of Distributions from git://github.com/JuliaStats/Distributions.jl.git
INFO: Cloning cache of NumericExtensions from git://github.com/lindahua/NumericExtensions.jl.git
INFO: Cloning cache of Stats from git://github.com/JuliaStats/Stats.jl.git
INFO: Installing Distributions v0.2.7
INFO: Installing NumericExtensions v0.2.17
INFO: Installing Stats v0.2.6
INFO: REQUIRE updated.
julia> Pkg.status()
Required packages:
- Distributions 0.2.7
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.6
Это делается путем добавления Distributions в ваш файл ~/.julia/v0.5/REQUIRE. Затем запускается Pkg.resolve() с этими новыми требованиями, что приводит к выводу о том, что пакет Distributions должен быть установлен, поскольку он необходим, но не установлен. Как уже говорилось, вы можете добиться того же, отредактировав файл ~/.julia/v0.5/REQUIRE вручную, а затем сами запустив Pkg.resolve():
$ echo UTF16 >> ~/.julia/v0.5/REQUIRE julia> Pkg.resolve() INFO: Cloning cache of UTF16 from git://github.com/nolta/UTF16.jl.git INFO: Installing UTF16 v0.2.0 julia> Pkg.status() Required packages: - Distributions 0.2.7 - UTF16 0.2.0 Additional packages: - NumericExtensions 0.2.17 - Stats 0.2.6
Это функционально эквивалентно вызову Pkg.add("UTF16"), за исключением того, что Pkg.add() не изменяет REQUIRE до после завершения установки, поэтому, если возникнут проблемы, REQUIRE останется таким, как было до вызова Pkg.add(). Формат файла REQUIRE описан в Спецификации требований; он позволяет, среди прочего, требовать определенных диапазонов версий пакетов.
Когда вы решаете, что больше не хотите иметь пакет, вы можете использовать Pkg.rm() для удаления требования к нему из файла REQUIRE.
julia> Pkg.rm("Distributions")
INFO: Removing Distributions v0.2.7
INFO: Removing Stats v0.2.6
INFO: Removing NumericExtensions v0.2.17
INFO: REQUIRE updated.
julia> Pkg.status()
Required packages:
- UTF16 0.2.0
julia> Pkg.rm("UTF16")
INFO: Removing UTF16 v0.2.0
INFO: REQUIRE updated.
julia> Pkg.status()
No packages installed.
Еще раз, это эквивалентно редактированию файла REQUIRE для удаления строки с каждым именем пакета, а затем запуску Pkg.resolve() для обновления набора установленных пакетов, соответствующего требованиям. Хотя Pkg.add() и Pkg.rm() удобны для добавления и удаления требований для одного пакета, когда вы хотите добавить или удалить несколько пакетов, вы можете вызвать Pkg.edit() для ручного изменения содержимого REQUIRE и затем соответствующим образом обновить ваши пакеты. Pkg.edit() не отменяет содержимое REQUIRE если Pkg.resolve() завершится неудачно — вам нужно снова запустить Pkg.edit(), чтобы исправить содержимое файлов самим.
Поскольку менеджер пакетов использует libgit2 для управления репозиториями пакетов Git, пользователи могут столкнуться с проблемами протокола (например, если они находятся за брандмауэром) при выполнении Pkg.add(). По умолчанию, ко всем GitHub-пакетам будет доступ через ‘https’; это значение по умолчанию может быть изменено с помощью вызова Pkg.setprotocol!(). Следующая команда может быть запущена из командной строки, чтобы сообщить git использовать ‘https’ вместо протокола ‘git’ при клонировании всех репозиториев, где бы они ни находились:
git config --global url."https://".insteadOf git://
Однако, это изменение будет системным, и поэтому предпочтительнее использовать Pkg.setprotocol!().
Установка пакетов офлайн
Для компьютеров без подключения к Интернету пакеты можно установить, скопировав корневой каталог пакета (указанный Pkg.dir()) с компьютера с той же операционной системой и средой.
Pkg.add() выполняет следующие действия в корневом каталоге пакета:
- Добавляет имя пакета в
REQUIRE. - Скачивает пакет в
.cache, затем копирует пакет в корневой каталог пакета. - Рекурсивно выполняет шаг 2 для всех пакетов, перечисленных в файле
REQUIREпакета. - Запускает
Pkg.build()
Предупреждение
Копирование установленных пакетов с другого компьютера хрупко для пакетов, требующих двоичных внешних зависимостей. Такие пакеты могут выйти из строя из-за различий в версиях операционных систем, средах сборки и/или зависимостях абсолютных путей.
Установка незарегистрированных пакетов
Пакеты Julia — это просто репозитории Git, клонируемые через любой из поддерживаемых git протоколов, и содержащие код Julia, который соответствует определенным соглашениям об организации. Официальные пакеты Julia зарегистрированы в репозитории METADATA.jl, доступном по известному адресу [1]. Команды Pkg.add() и Pkg.rm() в предыдущем разделе взаимодействуют с зарегистрированными пакетами, но менеджер пакетов также может устанавливать и работать с незарегистрированными пакетами. Для установки незарегистрированного пакета используйте Pkg.clone(url), где url — это URL git, с которого можно клонировать пакет:
julia> Pkg.clone("git://example.com/path/to/Package.jl.git")
INFO: Cloning Package from git://example.com/path/to/Package.jl.git
Cloning into 'Package'...
remote: Counting objects: 22, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 22 (delta 8), reused 22 (delta 8)
Receiving objects: 100% (22/22), 2.64 KiB, done.
Resolving deltas: 100% (8/8), done.
По соглашению, имена репозиториев Julia оканчиваются на .jl (дополнительное .git указывает на «голый» репозиторий git), что предотвращает их коллизии с репозиториями других языков, а также делает пакеты Julia легко находимыми в поисковых системах. Однако, когда пакеты установлены в вашем каталоге .julia/v0.5, расширение становится избыточным, поэтому мы его опускаем.
Если не зарегистрированные пакеты содержат файл REQUIRE в верхней части своей структуры исходного кода, этот файл будет использован для определения, от каких зарегистрированных пакетов зависит не зарегистрированный пакет, и они будут автоматически установлены. Незарегистрированные пакеты участвуют в той же логике разрешения версий, что и зарегистрированные пакеты, поэтому версии установленных пакетов будут корректироваться по мере необходимости для удовлетворения требований как зарегистрированных, так и незарегистрированных пакетов.
| [1] | Официальный набор пакетов находится по адресу https://github.com/JuliaLang/METADATA.jl, но отдельные лица и организации могут легко использовать другой репозиторий метаданных. Это позволяет контролировать, какие пакеты доступны для автоматической установки. Можно разрешить только проверенные и одобренные версии пакетов, а также сделать доступными частные пакеты или форки. Подробности см. в разделе Настройка репозитория METADATA. |
Обновление пакетов
Когда разработчики пакетов публикуют новые зарегистрированные версии пакетов, которые вы используете, вы, конечно, захотите получить новые версии. Чтобы получить последние и лучшие версии всех ваших пакетов, просто выполните Pkg.update():
julia> Pkg.update() INFO: Updating METADATA... INFO: Computing changes... INFO: Upgrading Distributions: v0.2.8 => v0.2.10 INFO: Upgrading Stats: v0.2.7 => v0.2.8
Первый шаг по обновлению пакетов — это получение новых изменений в ~/.julia/v0.5/METADATA и проверка наличия новых опубликованных версий зарегистрированных пакетов. После этого Pkg.update() пытается обновить пакеты, которые взяты с ветки и не содержат изменений (т.е. к файлам, отслеживаемым git, не было внесено изменений), затянув изменения из репозитория upstream пакета. Изменения upstream будут применены только в том случае, если не требуется слияние или перебазирование — т.е. если ветка может быть “быстро перемещена”. Если ветка не может быть быстро перемещена, предполагается, что вы работаете с ней и обновите репозиторий самостоятельно.
Наконец, процесс обновления пересчитывает оптимальный набор версий пакетов для установки, чтобы удовлетворить ваши требования верхнего уровня и требования «фиксированных» пакетов. Пакет считается фиксированным, если он относится к одному из следующих:
-
Незарегистрированный: пакет отсутствует в
METADATA— вы установили его с помощьюPkg.clone(). - Взятый с ветки: репозиторий пакета находится на ветке разработки.
- Измененный: в репозитории были внесены изменения в файлы.
Если это так, пакетный менеджер не может свободно изменять установленную версию пакета, поэтому его требования должны удовлетворяться любыми другими версиями пакетов, которые он выбирает. Для определения того, что должно быть установлено, используется сочетание требований верхнего уровня в ~/.julia/v0.5/REQUIRE и требований фиксированных пакетов.
Вы также можете обновить только подмножество установленных пакетов, передав аргументы функции Pkg.update. В этом случае будут обновлены только указанные пакеты и их зависимости:
julia> Pkg.update("Example")
INFO: Updating METADATA...
INFO: Computing changes...
INFO: Upgrading Example: v0.4.0 => 0.4.1
Этот процесс частичного обновления все еще вычисляет новый набор версий пакетов в соответствии с требованиями верхнего уровня и «фиксированными» пакетами, но он дополнительно рассматривает все другие пакеты, кроме явно указанных, и их зависимости как фиксированные.
Взятие с ветки, фиксация и освобождение
Вам может потребоваться использовать master версию пакета, а не одну из зарегистрированных версий. Может быть, есть исправления или функциональность на master, которые вам нужны, которые еще не опубликованы в каких-либо зарегистрированных версиях, или вы являетесь разработчиком пакета и вам нужно внести изменения в master или какую-то другую ветку разработки. В таких случаях вы можете использовать Pkg.checkout(pkg) для взятия с ветки master pkg или Pkg.checkout(pkg,branch) для взятия с другой ветки:
julia> Pkg.add("Distributions")
INFO: Installing Distributions v0.2.9
INFO: Installing NumericExtensions v0.2.17
INFO: Installing Stats v0.2.7
INFO: REQUIRE updated.
julia> Pkg.status()
Required packages:
- Distributions 0.2.9
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.7
julia> Pkg.checkout("Distributions")
INFO: Checking out Distributions master...
INFO: No packages to install, update or remove.
julia> Pkg.status()
Required packages:
- Distributions 0.2.9+ master
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.7
Сразу после установки Distributions с помощью Pkg.add() он находится на самой последней зарегистрированной версии — 0.2.9 на момент написания данной статьи. Затем, после запуска Pkg.checkout("Distributions"), вы можете увидеть из вывода Pkg.status(), что Distributions находится на незарегистрированной версии, большей, чем 0.2.9, указанной «псевдоверсией» 0.2.9+.
Когда вы берете незарегистрированную версию пакета с ветки, копия файла REQUIRE в репозитории пакета имеет приоритет над любыми зарегистрированными требованиями в METADATA, поэтому важно, чтобы разработчики сохраняли этот файл точным и актуальным, отражая фактические требования текущей версии пакета. Если файл REQUIRE в репозитории пакета неверный или отсутствует, зависимости могут быть удалены при взятии пакета с ветки. Этот файл также используется для заполнения недавно опубликованных версий пакета, если вы используете API, который предоставляет Pkg для этого (описано ниже).
Когда вы решите, что больше не хотите иметь пакет на ветке, вы можете «освободить» его под контроль пакетного менеджера с помощью Pkg.free(pkg):
julia> Pkg.free("Distributions")
INFO: Freeing Distributions...
INFO: No packages to install, update or remove.
julia> Pkg.status()
Required packages:
- Distributions 0.2.9
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.7
После этого, поскольку пакет находится на зарегистрированной версии и не находится на ветке, его версия будет обновляться по мере публикации новых зарегистрированных версий пакета.
Если вы хотите зафиксировать пакет на определенной версии, чтобы вызов Pkg.update() не менял версию пакета, вы можете использовать функцию Pkg.pin():
julia> Pkg.pin("Stats")
INFO: Creating Stats branch pinned.47c198b1.tmp
julia> Pkg.status()
Required packages:
- Distributions 0.2.9
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.7 pinned.47c198b1.tmp
После этого пакет Stats останется зафиксированным на версии 0.2.7 — или, точнее, на коммите 47c198b1, но поскольку версии постоянно связаны с определенным git-хэшем, это то же самое. Pkg.pin() работает, создавая временную ветку для коммита, на котором вы хотите зафиксировать пакет, а затем беря эту ветку. По умолчанию он фиксирует пакет на текущем коммите, но вы можете выбрать другую версию, передав второй аргумент:
julia> Pkg.pin("Stats",v"0.2.5")
INFO: Creating Stats branch pinned.1fd0983b.tmp
INFO: No packages to install, update or remove.
julia> Pkg.status()
Required packages:
- Distributions 0.2.9
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.5 pinned.1fd0983b.tmp
Теперь пакет Stats зафиксирован на коммите 1fd0983b, что соответствует версии 0.2.5. Когда вы решите «отменить фиксацию» пакета и снова позволить пакетному менеджеру обновить его, вы можете использовать Pkg.free(), как вы бы это сделали, чтобы перейти с любой ветки:
julia> Pkg.free("Stats")
INFO: Freeing Stats...
INFO: No packages to install, update or remove.
julia> Pkg.status()
Required packages:
- Distributions 0.2.9
Additional packages:
- NumericExtensions 0.2.17
- Stats 0.2.7
После этого пакет Stats снова управляется пакетным менеджером, и будущие вызовы Pkg.update() будут обновлять его до более новых версий при их публикации. Временная ветка pinned.1fd0983b.tmp остается в вашем локальном репозитории Stats, но поскольку ветки git очень легкие, это не имеет большого значения; если вы захотите их очистить, вы можете зайти в репозиторий и удалить эти ветки [2].
| [2] | Пакеты, которые не находятся на ветках, также будут помечены как измененные, если вы внесёте изменения в репозиторий, но это менее распространённая практика. |
Настройка репозитория METADATA
По умолчанию Julia предполагает, что вы будете использовать репозиторий официального METADATA.jl для загрузки и установки пакетов. Вы также можете указать другое местоположение репозитория метаданных. Общий подход заключается в том, чтобы поддерживать свою ветку metadata-v2 в актуальном состоянии с официальной веткой Julia и добавить другую ветку со своими пользовательскими пакетами. Вы можете инициализировать свой локальный репозиторий метаданных с использованием этого пользовательского местоположения и ветки, а затем периодически перебазировать свою пользовательскую ветку с официальной веткой metadata-v2. Чтобы использовать пользовательский репозиторий и ветку, выполните следующую команду:
julia> Pkg.init("https://me.example.com/METADATA.jl.git", "branch")
Аргумент ветки необязателен и по умолчанию равен metadata-v2. После инициализации файл с именем META_BRANCH в вашем пути ~/.julia/vX.Y/ будет отслеживать ветку, с которой был инициализирован ваш репозиторий METADATA. Если вы хотите изменить ветку, вам необходимо либо изменить файл META_BRANCH непосредственно (будьте осторожны!), либо удалить каталог vX.Y и повторно инициализировать свой репозиторий METADATA с помощью команды Pkg.init.
© 2009–2016 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/release-0.5/manual/packages/