Справочник по Go Modules
Введение
Модули — это способ, которым Go управляет зависимостями.
Данный документ представляет собой подробное справочное руководство по системе модулей Go. Для введения в создание проектов на Go см. Как писать код на Go. Для получения информации о применении модулей, миграции проектов на модули и других темах см. серию блогов, начиная с Using Go Modules.
Модули, пакеты и версии
Модуль — это коллекция пакетов, которые выпускаются, версионируются и распространяются вместе. Модули могут быть загружены непосредственно из репозиториев управления версиями или из прокси-серверов модулей.
Модуль идентифицируется по пути модуля, который объявляется в go.mod файле, вместе с информацией о зависимостях модуля. Корневой каталог модуля — это каталог, содержащий файл go.mod. Главный модуль — это модуль, содержащий каталог, из которого вызывается команда go.
Каждый пакет внутри модуля — это коллекция исходных файлов в одном каталоге, которые компилируются вместе. Путь пакета — это путь модуля, объединённый с подкаталогом, содержащим пакет (относительно корня модуля). Например, модуль "golang.org/x/net" содержит пакет в каталоге "html". Путь этого пакета — "golang.org/x/net/html".
Пути модулей
Путь модуля — это каноническое имя модуля, объявленное с помощью module директивы в go.mod файле модуля. Путь модуля является префиксом для путей пакетов внутри модуля.
Путь модуля должен описывать как то, что делает модуль, так и где его можно найти. Как правило, путь модуля состоит из пути корневого каталога репозитория, каталога внутри репозитория (обычно пустого) и суффикса основной версии (только для основной версии 2 и выше).
- Путь корневого каталога репозитория — это часть пути модуля, соответствующая корневому каталогу репозитория системы управления версиями, где разрабатывается модуль. Большинство модулей определены в корневом каталоге репозитория, поэтому обычно это весь путь. Например,
golang.org/x/net— это путь корневого каталога репозитория для модуля с таким же именем. См. Поиск репозитория по пути модуля для информации о том, как командаgoнаходит репозиторий с помощью HTTP-запросов, полученных из пути модуля. - Если модуль не определён в корневом каталоге репозитория, подкаталог модуля — это часть пути модуля, которая указывает на каталог, не включая суффикс основной версии. Он также служит префиксом для тегов семантической версии. Например, модуль
golang.org/x/tools/goplsнаходится в подкаталогеgoplsрепозитория с корневым путёмgolang.org/x/tools, поэтому он имеет подкаталог модуляgopls. См. Сопоставление версий с коммитами и Каталоги модулей внутри репозитория. - Если модуль выпускается с основной версией 2 или выше, путь модуля должен заканчиваться суффиксом основной версии, таким как
/v2. Это может быть или не быть частью имени подкаталога. Например, модуль с путёмgolang.org/x/repo/sub/v2может находиться в подкаталоге/subили/sub/v2репозиторияgolang.org/x/repo.
Если модуль может быть зависимостью для других модулей, необходимо соблюдать следующие правила, чтобы команда go могла находить и скачивать модуль. Также существуют несколько лексических ограничений на символы, разрешённые в путях модулей.
Модуль, который никогда не будет загружаться как зависимость любого другого модуля, может использовать любой допустимый путь пакета в качестве пути модуля, но должен убедиться, что он не конфликтует с путями, которые могут использоваться зависимостями модуля или стандартной библиотекой Go. Стандартная библиотека Go использует пути пакетов, которые не содержат точку в первом элементе пути, и команда go не пытается разрешить такие пути с сетевых серверов. Пути example и test зарезервированы для пользователей: они не будут использоваться в стандартной библиотеке и подходят для использования в самодостаточных модулях, таких как те, что определены в учебниках или примерах кода или созданные и изменяемые в рамках тестирования.
Версии
Версия обозначает неизменную снимок модуля, который может быть релизом или предрелизом. Каждая версия начинается с буквы v, за которой следует семантическая версия. См. Семантическое версионирование 2.0.0 для получения подробной информации о форматировании, интерпретации и сравнении версий.
Вкратце, семантическая версия состоит из трёх неотрицательных целых чисел (основная, дополнительная и исправляющая версии, слева направо), разделённых точками. Исправляющая версия может быть дополнена необязательной строкой предрелиза, начинающейся с дефиса. Строка предрелиза или исправляющая версия могут быть дополнены строкой метаданных сборки, начинающейся с плюса. Например, v0.0.0, v1.12.134, v8.0.5-pre и v2.0.9+meta являются допустимыми версиями.
Каждая часть версии указывает, является ли версия стабильной и совместима ли она с предыдущими версиями.
- Основная версия должна быть увеличена, а дополнительная и исправляющая версии должны быть установлены в ноль после внесения обратно несовместимых изменений в публичный интерфейс модуля или документированную функциональность, например, после удаления пакета.
- Дополнительная версия должна быть увеличена, а исправляющая версия — в ноль после внесения обратно совместимых изменений, например, после добавления новой функции.
- Исправляющая версия должна быть увеличена после изменений, которые не влияют на публичный интерфейс модуля, такие как исправление ошибок или оптимизация.
- Суффикс предрелиза указывает, что версия является предрелизом. Предрелизные версии сортируются перед соответствующими релизными версиями. Например,
v1.2.3-preидёт передv1.2.3. - Суффикс метаданных сборки игнорируется при сравнении версий. Команда
goпринимает версии с метаданными сборки и преобразует их в псевдо-версии, чтобы сохранить полный порядок между версиями.- Специальный суффикс
+incompatibleобозначает версию, выпущенную до перехода к модулям с основной версией 2 или выше (см. Совместимость с репозиториями, не использующими модули). - Специальный суффикс
+dirtyдобавляется к информации о версии двоичного файла, если он был собран с использованием инструментария Go версии 1.24 или выше внутри допустимого локального репозитория системы управления версиями (VCS), содержащего не зафиксированные изменения в рабочем каталоге.
- Специальный суффикс
Версия считается нестабильной, если её основная версия равна 0 или если у неё есть суффикс предрелизной версии. Нестабильные версии не подчиняются требованиям совместимости. Например, v0.2.0 может быть несовместима с v0.1.0, а v1.5.0-beta может быть несовместима с v1.5.0.
Go может получать доступ к модулям в системах контроля версий, используя теги, ветки или ревизии, которые не соответствуют этим соглашениям. Однако внутри основного модуля команда go автоматически преобразует имена ревизий, не соответствующие стандарту, в канонические версии. Команда go также удаляет суффиксы метаданных сборки (кроме +incompatible) в рамках этого процесса. Это может привести к созданию псевдоверсии — предрелизной версии, которая кодирует идентификатор ревизии (например, хэш коммита) и временную метку из системы контроля версий. Например, команда go get golang.org/x/net@daa7c041 преобразует хэш коммита daa7c041 в псевдоверсию v0.0.0-20191109021931-daa7c04131f5. Канонические версии требуются за пределами основного модуля, и команда go выдаст ошибку, если в файле go.mod будет указана неканоническая версия, например, master.
Псевдоверсии
Псевдоверсия — это специально отформатированная предрелизная версия, которая кодирует информацию о конкретной ревизии в репозитории системы контроля версий. Например, v0.0.0-20191109021931-daa7c04131f5 является псевдоверсией.
Псевдоверсии могут ссылаться на ревизии, для которых не доступны семантические теги версий. Они могут использоваться для тестирования коммитов до создания тегов версий, например, в разработческой ветке.
Каждая псевдоверсия состоит из трёх частей:
- Префикс базовой версии (
vX.0.0илиvX.Y.Z-0), который либо выводится из семантического тега версии, предшествующего ревизии, либо равенvX.0.0, если такого тега нет. - Временная метка (
yyyymmddhhmmss), которая соответствует времени создания ревизии в формате UTC. В Git это время коммита, а не время автора. - Идентификатор ревизии (
abcdefabcdef), который представляет собой 12-символьный префикс хэша коммита или, в случае Subversion, нулированное число ревизии.
Каждая псевдоверсия может быть одной из трёх форм, в зависимости от базовой версии. Эти формы обеспечивают, что псевдоверсия будет больше своей базовой версии, но меньше следующей тегированной версии.
vX.0.0-yyyymmddhhmmss-abcdefabcdefиспользуется, когда базовая версия неизвестна. Как и во всех версиях, основная версияXдолжна совпадать с суффиксом основной версии модуля.vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdefиспользуется, когда базовая версия представляет собой предрелизную версию, например,vX.Y.Z-pre.vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdefиспользуется, когда базовая версия является релизной версией, например,vX.Y.Z. Например, если базовая версияv1.2.3, псевдоверсия может бытьv1.2.4-0.20191109021931-daa7c04131f5.
Одна псевдо-версия может ссылаться на тот же коммит, используя разные базовые версии. Это происходит естественным образом, когда более низкая версия тегируется после того, как была создана псевдо-версия.
Эти формы дают псевдо-версиям две полезные характеристики:
- Псевдо-версии с известными базовыми версиями сортируются выше, чем соответствующие им версии, но ниже, чем другие предрелизные версии для более поздних версий.
- Псевдо-версии с одинаковым префиксом базовой версии сортируются хронологически.
Команда go выполняет несколько проверок, чтобы убедиться, что авторы модулей имеют контроль над тем, как псевдо-версии сравниваются с другими версиями, и что псевдо-версии указывают на изменения, которые действительно являются частью истории коммитов модуля.
- Если указана базовая версия, то должен существовать соответствующий семантический тег версии, который является предком изменения, описываемого псевдо-версией. Это предотвращает возможность обхода минимального выбора версии с помощью псевдо-версии, которая сравнивается выше всех тегированных версий, например,
v1.999.999-99999999999999-daa7c04131f5. - Временная метка должна совпадать с временной меткой изменения. Это предотвращает атакующих от переполнения прокси модулей неограниченным количеством в основном одинаковых псевдо-версий. Это также предотвращает потребителей модулей от изменения относительного порядка версий.
- Изменение должно быть предком одной из веток или тегов репозитория модуля. Это предотвращает атакующих от ссылки на неподтверждённые изменения или запросы на слияние.
Псевдо-версии никогда не нужно вводить вручную. Многие команды принимают хэш коммита или имя ветки и автоматически преобразуют его в псевдо-версию (или тегированную версию, если она доступна). Например:
<code>go get example.com/mod@master go list -m -json example.com/mod@abcd1234 </code>
Суффиксы мажорных версий
Начиная с мажорной версии 2, пути модулей должны содержать суффикс мажорной версии вроде /v2, соответствующий мажорной версии. Например, если модуль имеет путь example.com/mod в версии v1.0.0, он должен иметь путь example.com/mod/v2 в версии v2.0.0.
Суффиксы мажорных версий реализуют правило совместимости импортов:
Если старый пакет и новый пакет имеют одинаковый путь импорта, новый пакет должен быть обратно совместим с старым пакетом.
По определению, пакеты в новой мажорной версии модуля не являются обратно совместимыми с соответствующими пакетами в предыдущей мажорной версии. Следовательно, начиная с v2, пакеты требуют новых путей импорта. Это достигается добавлением суффикса мажорной версии к пути модуля. Поскольку путь модуля является префиксом пути импорта каждого пакета внутри модуля, добавление суффикса мажорной версии к пути модуля обеспечивает уникальный путь импорта для каждой несовместимой версии.
Суффиксы основных версий недопустимы в основных версиях v0 или v1. Нет необходимости изменять путь модуля между v0 и v1, поскольку версии v0 нестабильны и не имеют гарантий совместимости. Кроме того, для большинства модулей версия v1 обратно совместима с последней версией v0; версия v1 действует как обязательство по совместимости, а не как указание на несовместимые изменения по сравнению с v0.
В особых случаях пути модулей, начинающиеся с gopkg.in/, всегда должны иметь суффикс основной версии, даже в версиях v0 и v1. Суффикс должен начинаться с точки, а не со слэша (например, gopkg.in/yaml.v2).
Суффиксы основных версий позволяют нескольким основным версиям одного модуля сосуществовать в одном и том же сборке. Это может быть необходимо из-за диамантной проблемы зависимостей. Обычно, если модуль требуется в двух разных версиях через транзитивные зависимости, будет использована более высокая версия. Однако, если две версии несовместимы, ни одна из них не сможет удовлетворить всех клиентов. Поскольку несовместимые версии должны иметь разные номера основных версий, они также должны иметь разные пути модулей из-за суффиксов основных версий. Это разрешает конфликт: модули с различными суффиксами рассматриваются как отдельные модули, и их пакеты — даже пакеты из одной и той же поддиректории относительно корней модулей — являются различными.
Многие проекты на Go выпускали версии v2 и выше без использования суффиксов основных версий до перехода к модулям (возможно, даже до того, как модули были представлены). Эти версии аннотированы тегом сборки +incompatible (например, v2.0.0+incompatible). См. Совместимость с репозиториями, не являющимися модулями для получения дополнительной информации.
Определение модуля для пакета
Когда команда go загружает пакет с использованием пути пакета, ей необходимо определить, какой модуль предоставляет пакет.
Команда go начинает поиск в списке сборки модулей, пути которых являются префиксами пути пакета. Например, если импортируется пакет example.com/a/b, и модуль example.com/a находится в списке сборки, команда go проверит, содержит ли example.com/a пакет, находящийся в директории b. По крайней мере один файл с расширением .go должен присутствовать в директории, чтобы она считалась пакетом. Ограничения сборки не применяются в этом случае. Если ровно один модуль в списке сборки предоставляет пакет, используется этот модуль. Если ни один модуль не предоставляет пакет или если два или более модуля предоставляют пакет, команда go выдает ошибку. Флаг -mod=mod указывает команде go попытаться найти новые модули, предоставляющие недостающие пакеты, и обновить go.mod и go.sum. Команды go get и go mod tidy делают это автоматически.
Когда команда go ищет новый модуль для пути пакета, она проверяет переменную окружения
GOPROXY, которая представляет собой список URL-адресов прокси, разделённых запятыми, или
ключи direct или off. URL-адрес прокси указывает, что команда go должна
связаться с модульным прокси, используя GOPROXY
протокол. direct указывает, что команда go должна
связаться с системой управления версиями. off указывает, что связываться не нужно.
Переменные окружения GOPRIVATE и GONOPROXY переменные окружения также могут быть использованы для управления этим поведением.
Для каждого элемента в списке GOPROXY команда go запрашивает последнюю версию каждого
пути модуля, который может предоставить пакет (то есть каждый префикс пути пакета). Для каждого успешно
запрошенного пути модуля команда go скачает модуль в последней версии и проверит, содержит ли
модуль запрашиваемый пакет. Если один или несколько модулей содержат запрашиваемый пакет, будет использован
модуль с самым длинным путём. Если найдены один или несколько модулей, но ни один не содержит запрашиваемый
пакет, будет выдана ошибка. Если модули не найдены, команда go попробует следующий элемент в списке
GOPROXY. Если элементы закончились, будет выдана ошибка.
Например, предположим, что команда go ищет модуль, который предоставляет пакет
golang.org/x/net/html, и переменная GOPROXY установлена в
https://corp.example.com,https://proxy.golang.org. Команда go может выполнить
следующие запросы:
- На
https://corp.example.com/(параллельно):- Запрос последней версии
golang.org/x/net/html - Запрос последней версии
golang.org/x/net - Запрос последней версии
golang.org/x - Запрос последней версии
golang.org
- Запрос последней версии
- На
https://proxy.golang.org/, если все запросы кhttps://corp.example.com/завершились с ошибками 404 или 410:- Запрос последней версии
golang.org/x/net/html - Запрос последней версии
golang.org/x/net - Запрос последней версии
golang.org/x - Запрос последней версии
golang.org
- Запрос последней версии
После того как будет найден подходящий модуль, команда go добавит новое
требование с путём и версией нового модуля в файл go.mod
основного модуля. Это гарантирует, что при последующей загрузке того же пакета будет использован тот же модуль
в той же версии. Если резолвленный пакет не импортируется пакетом в основном модуле, новое требование будет
снабжено комментарием // indirect.
go.mod files
Модуль определяется текстовым файлом, закодированным в UTF-8 и названным go.mod, который находится в корневой директории модуля. Файл go.mod ориентирован на строки. Каждая строка содержит одну директиву, состоящую из ключевого слова, за которым следуют аргументы. Например:
<code>module example.com/my/thing go 1.23.0 require example.com/other/thing v1.0.2 require example.com/new/thing/v2 v2.3.4 exclude example.com/old/thing v1.2.3 replace example.com/bad/thing v1.4.5 => example.com/good/thing v1.4.5 retract [v1.9.0, v1.9.5] </code>
Ключевое слово можно опустить в соседних строках, чтобы создать блок, как в импортах Go.
<code>require ( example.com/new/thing/v2 v2.3.4 example.com/old/thing v1.2.3 ) </code>
Файл go.mod предназначен для того, чтобы быть читаемым человеком и записываемым машиной. Команда go предоставляет несколько подкоманд, которые изменяют файлы go.mod. Например, go get может обновлять или понижать конкретные зависимости. Команды, которые загружают граф модулей, будут автоматически обновлять файл go.mod при необходимости. go mod edit может выполнять низкоуровневые правки. Пакет golang.org/x/mod/modfile может быть использован программами на Go для выполнения тех же изменений программно.
Файл go.mod требуется для главного модуля и для любого модуля-замены, указанного с локальным путём к файлу. Однако, модуль без явного файла go.mod всё ещё может быть требуемым как зависимость или использоваться как замена, указанная с путём модуля и версией; см. Совместимость с репозиториями, не являющимися модулями.
Лексические элементы
Когда файл go.mod парсится, его содержимое разбивается на последовательность токенов. Существует несколько типов токенов: пробелы, комментарии, пунктуация, ключевые слова, идентификаторы и строки.
Пробельные символы состоят из пробелов (U+0020), табуляций (U+0009), возвратов каретки (U+000D) и символов новой строки (U+000A). Пробельные символы, кроме символов новой строки, не влияют на разбор, кроме как для разделения токенов, которые иначе были бы объединены. Символы новой строки являются значимыми токенами.
Комментарии начинаются с // и продолжаются до конца строки. Комментарии вида /* */ не допускаются.
Пунктуационные токены включают (, ) и =>.
Ключевые слова отличают различные виды директив в файле go.mod. Допустимые ключевые слова: module, go, require, replace, exclude и retract.
Идентификаторы — это последовательности непробельных символов, такие как пути модулей или семантические версии.
Строки — это последовательности символов, заключённые в кавычки. Существует два вида строк:
интерпретируемые строки, начинающиеся и заканчивающиеся двойными кавычками (", U+0022), и
необработанные строки, начинающиеся и заканчивающиеся обратными апострофами (`, U+0060).
Интерпретируемые строки могут содержать escape-последовательности, состоящие из обратной косой черты
(\, U+005C), за которой следует другой символ. Эскейп-последовательность, представляющая собой
двойную кавычку (\"), не завершает интерпретируемую строку. Необработанное значение интерпретируемой
строки — это последовательность символов между кавычками, при этом каждая escape-последовательность заменяется
символом, следующим за обратной косой чертой (например, \" заменяется на ", \n заменяется на n).
В отличие от этого, необработанное значение необработанной строки — это просто последовательность символов
между обратными апострофами; обратные косые черты внутри необработанных строк не имеют специального значения.
Идентификаторы и строки взаимозаменяемы в грамматике файла go.mod.
Пути и версии модулей
Большинство идентификаторов и строк в файле go.mod представляют собой либо пути модулей, либо версии.
Путь модуля должен соответствовать следующим требованиям:
- Путь должен состоять из одного или нескольких элементов, разделённых косыми чертами (
/, U+002F). Он не должен начинаться или заканчиваться косой чертой. - Каждый элемент пути — это непустая строка, состоящая из букв ASCII, цифр ASCII и ограниченной
ASCII пунктуации (
-,.,_и~). - Элемент пути не может начинаться или заканчиваться точкой (
., U+002E). - Префикс элемента до первой точки не должен быть зарезервированным именем файла в Windows,
независимо от регистра (
CON,com1,NuLи так далее). - Префикс элемента до первой точки не должен заканчиваться на тильду, за которой следуют
одна или более цифр (например,
EXAMPL~1.COM).
Если путь модуля указан в директиве require и не был заменён, или если путь модуля указан
в правой части директивы replace, команда go может потребоваться загрузить модуль с таким путём,
и должны быть выполнены дополнительные требования.
- Первый элемент пути (до первой косой черты, если она есть), по соглашению,
доменное имя, должен содержать только строчные буквы ASCII, цифры ASCII, точки (
., U+002E) и тире (-, U+002D); он должен содержать хотя бы одну точку и не может начинаться с тире. - Для последнего элемента пути вида
/vN, гдеNвыглядит как число (цифры ASCII и точки),Nне должно начинаться с нуля, не должно быть/v1и не должно содержать точки.- Для путей, начинающихся с
gopkg.in/, это требование заменяется требованием, что путь должен соответствовать соглашениям сервиса gopkg.in.
- Для путей, начинающихся с
Версии в файлах go.mod могут быть каноническими или
неканоническими.
Каноническая версия начинается с буквы v, за которой следует семантическая версия,
соответствующая спецификации Semantic Versioning 2.0.0.
См. Versions для получения дополнительной информации.
Большинство других идентификаторов и строк могут использоваться в качестве неканонических версий, хотя
существуют некоторые ограничения, чтобы избежать проблем с файловыми системами, репозиториями и
прокси модулей. Неканонические версии допускаются только в основном модуле
файла go.mod. Команда go попытается заменить каждую неканоническую версию эквивалентной канонической версией,
когда она автоматически обновит файл go.mod.
В местах, где путь модуля связан с версией (как в директивах require,
replace и exclude), последний элемент пути должен быть согласован с версией.
См. Major version suffixes.
Грамматика
Синтаксис go.mod задается ниже с использованием расширенной формы Бэкуса — Наура (EBNF).
См. раздел «Нотация» в Спецификации языка Go
для получения подробностей о синтаксисе EBNF.
<code>GoMod = { Directive } .
Directive = ModuleDirective |
GoDirective |
ToolDirective |
IgnoreDirective |
RequireDirective |
ExcludeDirective |
ReplaceDirective |
RetractDirective .
</code>
Переводы, идентификаторы и строки обозначены как newline, ident и
string соответственно.
Пути модулей и версии обозначены как ModulePath и Version.
<code>ModulePath = ident | string . /* see restrictions above */ Version = ident | string . /* see restrictions above */ </code>
module директива
Директива module определяет путь основного модуля. Файл
go.mod должен содержать ровно одну директиву module.
<code>ModuleDirective = "module" ( ModulePath | "(" newline ModulePath newline ")" ) newline .
</code>
Пример:
<code>module golang.org/x/net </code>
Устаревшие модули
Модуль может быть помечен как устаревший в блоке комментариев, содержащем строку
Deprecated: (с учетом регистра) в начале абзаца. Сообщение об устаревании начинается после двоеточия
и продолжается до конца абзаца. Комментарии могут появляться непосредственно перед директивой
module или после нее на той же строке.
Пример:
<code>// Deprecated: use example.com/mod/v2 instead. module example.com/mod </code>
Начиная с Go 1.17, go list -m -u проверяет информацию обо всех
deprecated модулях в списке сборки. go get
проверяет deprecated модули, необходимые для сборки пакетов, указанных в командной строке.
Когда команда go извлекает информацию о deprecated модулях, она загружает файл
go.mod из версии, соответствующей запросу версии @latest, не учитывая
отзывы или исключения. Команда go загружает список
отозванных версий из того же файла go.mod.
Чтобы объявить модуль deprecated, автор может добавить комментарий // Deprecated: и
выпустить новую версию. Автор может изменить или удалить сообщение deprecated в более
поздней версии.
Объявление deprecated применяется ко всем минорным версиям модуля. Мажорные версии выше
v2 считаются отдельными модулями в этом смысле, поскольку их мажорные суффиксы
дают им уникальные пути модулей.
Сообщения deprecated предназначены для информирования пользователей о том, что модуль
больше не поддерживается, и для предоставления инструкций по миграции, например, на последнюю
мажорную версию. Отдельные минорные и патч-версии не могут быть объявлены deprecated;
для этого может быть более подходящим использование retract.
Директива go
Директива go указывает, что модуль был написан с предположением о семантике заданной
версии Go. Версия должна быть допустимой версией Go,
например, 1.14, 1.21rc1 или 1.23.0.
Директива go задаёт минимальную версию Go, необходимую для использования этого модуля.
До Go 1.21 директива была рекомендательной; теперь она является обязательной: инструментарий
Go отказывается использовать модули, объявляющие более новые версии Go.
Директива go служит входными данными для выбора используемого инструментария Go.
См. «Инструментарий Go» для получения подробной информации.
Директива go влияет на использование новых языковых возможностей:
- Для пакетов внутри модуля компилятор отклоняет использование языковых возможностей,
введённых после версии, указанной директивой
go. Например, если модуль имеет директивуgo 1.12, его пакеты не могут использовать числовые литералы вроде1_000_000, которые были введены в Go 1.13. - Если более старая версия Go собирает один из пакетов модуля и сталкивается с ошибкой
компиляции, то ошибка указывает, что модуль был написан для более новой версии Go.
Например, если модуль имеет
go 1.13, а пакет использует числовой литерал1_000_000, то при сборке с использованием Go 1.12 компилятор уведомит, что код написан для Go 1.13.
Директива go также влияет на поведение команды go:
- Начиная с версии
go 1.14, может быть включено автоматическое вендинг. Если файлvendor/modules.txtприсутствует и согласован сgo.mod, то явное использование флага-mod=vendorне требуется. - Начиная с версии
go 1.16, шаблон пакетовallсоответствует только пакетам, транзитивно импортированным пакетами и тестами в главном модуле. Это тот же набор пакетов, который сохраняется командойgo mod vendorс момента появления модулей. В более ранних версияхallтакже включал тесты пакетов, импортированных пакетами главного модуля, тесты этих пакетов и так далее. - Начиная с версии
go 1.17:- Файл
go.modсодержит явную директивуrequireдля каждого модуля, предоставляющего любой пакет, транзитивно импортированный пакетом или тестом в главном модуле. (В версияхgo 1.16и ниже, косвенная зависимость включается только в том случае, если выбор минимальной версии в противном случае выбрал бы другую версию.) Эта дополнительная информация позволяет выполнять сокращение графа модулей и ленивую загрузку модулей. - Поскольку косвенных зависимостей может быть гораздо больше, чем в предыдущих версиях
go, косвенные зависимости записываются в отдельный блок внутри файлаgo.mod. - Команда
go mod vendorпропускает файлыgo.modиgo.sumдля зависимостей, помещённых вvendor. (Это позволяет вызовам командыgoв подкаталогахvendorопределять корректный главный модуль.) - Команда
go mod vendorзаписывает версиюgoизgo.modкаждого зависимого модуля в файлvendor/modules.txt.
- Файл
- Начиная с версии
go 1.21:- Строка
goобъявляет минимально необходимую версию Go для использования с этим модулем. - Строка
goдолжна быть больше или равна строкеgoвсех зависимостей. - Команда
goбольше не пытается поддерживать совместимость с предыдущей более старой версией Go. - Команда
goболее осторожно обращается с хэшами файловgo.modв файлеgo.sum.
- Строка
Файл go.mod может содержать не более одной директивы go. Большинство команд добавят директиву go с текущей версией Go, если такой директивы нет.
Если директива go отсутствует, подразумевается версия go 1.16.
<code>GoDirective = "go" GoVersion newline . GoVersion = string | ident . /* valid release version; see above */ </code>
Пример:
<code>go 1.23.0 </code>
toolchain директива
toolchain директива объявляет рекомендуемую версию Go инструментария для использования с модулем.
Версия рекомендуемого Go инструментария не может быть меньше, чем требуемая версия Go,
объявленная в директиве go.
Директива toolchain влияет только тогда, когда модуль является основным модулем и версия
инструментария по умолчанию меньше версии рекомендуемого инструментария.
Для обеспечения воспроизводимости команда go записывает собственное имя инструментария в строку toolchain всякий раз,
когда она обновляет версию go в файле go.mod (обычно во время go get).
Для получения дополнительной информации см. «Go toolchains».
<code>ToolchainDirective = "toolchain" ToolchainName newline . ToolchainName = string | ident . /* valid toolchain name; see “Go toolchains” */ </code>
Пример:
<code>toolchain go1.21.0 </code>
godebug директива
godebug директива объявляет единственную настройку GODEBUG,
которая применяется, когда этот модуль является основным модулем.
Может присутствовать более одной такой строки, и они могут быть объединены.
Ошибка возникает, если основной модуль указывает ключ GODEBUG, который не существует.
Эффект от godebug key=value аналогичен наличию в каждом пакете, который компилируется,
исходного файла со строкой //go:debug key=value.
<code>GodebugDirective = "godebug" ( GodebugSpec | "(" newline { GodebugSpec } ")" newline ) .
GodebugSpec = GodebugKey "=" GodebugValue newline.
GodebugKey = GodebugChar { GodebugChar }.
GodebugValue = GodebugChar { GodebugChar }.
GodebugChar = любой непробельный символ, кроме , " ` ' (запятая и кавычки).
</code>
Пример:
<code>godebug default=go1.21 godebug ( panicnil=1 asynctimerchan=0 ) </code>
require директива
require директива объявляет минимально необходимую версию зависимости модуля.
Для каждой требуемой версии модуля команда go загружает файл go.mod для этой версии
и включает в себя требования из этого файла.
После загрузки всех требований команда go разрешает их с использованием
минимального выбора версий (MVS) для формирования
списка сборки.
Команда go автоматически добавляет комментарии // indirect для некоторых требований.
Комментарий // indirect указывает, что ни один пакет из требуемого модуля не импортируется напрямую
никаким пакетом в основном модуле.
Если go директива указывает go 1.16 или ниже, команда go
добавляет косвенное требование, когда выбранная версия модуля выше, чем уже предполагаемая (транзитивно)
другими зависимостями основного модуля. Это может произойти из-за явного обновления (go get -u ./...),
удаления другой зависимости, которая ранее устанавливалась требования (go mod tidy), или зависимости,
которая импортирует пакет без соответствующего требования в собственном файле go.mod
(например, зависимость, которая вообще не имеет файла go.mod).
Начиная с версии go 1.17, команда go добавляет косвенную зависимость для каждого модуля, который предоставляет любой пакет, импортированный (даже косвенно) пакетом или тестом в главном модуле или переданным в качестве аргумента в go get. Эти более подробные зависимости позволяют выполнять сокращение графа модулей и ленивую загрузку модулей.
<code>RequireDirective = "require" ( RequireSpec | "(" newline { RequireSpec } ")" newline ) .
RequireSpec = ModulePath Version newline .
</code>
Пример:
<code>require golang.org/x/net v1.2.3 require ( golang.org/x/crypto v1.4.5 // indirect golang.org/x/text v1.6.7 ) </code>
tool директива
Директива tool добавляет пакет в качестве зависимости текущего модуля. Она также делает его доступным для запуска с помощью команды go tool, если текущий рабочий каталог находится внутри этого модуля или внутри рабочей области, содержащей этот модуль.
Если пакет инструмента не находится в текущем модуле, должна присутствовать директива require, которая указывает версию инструмента для использования.
МетаПаттерн tool разрешается в список инструментов, определённых в go.mod текущего модуля, или в случае работы в режиме рабочей области — в объединение всех инструментов, определённых во всех модулях этой рабочей области.
<code>ToolDirective = "tool" ( ToolSpec | "(" newline { ToolSpec } ")" newline ) .
ToolSpec = ModulePath newline .
</code>
Пример:
<code>tool golang.org/x/tools/cmd/stringer tool ( example.com/module/cmd/a example.com/module/cmd/b ) </code>
ignore директива
Директива ignore заставляет команду go игнорировать пути к каталогам, разделённые косой чертой, а также любые файлы или каталоги, рекурсивно содержащиеся в них, при сопоставлении шаблонов пакетов.
Если путь начинается с ./, путь интерпретируется относительно корневого каталога модуля, и этот каталог, а также все каталоги или файлы, рекурсивно содержащиеся в нём, будут игнорироваться при сопоставлении шаблонов пакетов.
В противном случае, все каталоги с указанным путём на любом уровне в модуле, а также все каталоги или файлы, рекурсивно содержащиеся в них, будут игнорироваться.
<code>IgnoreDirective = "ignore" ( IgnoreSpec | "(" newline { IgnoreSpec } ")" newline ) .
IgnoreSpec = RelativeFilePath newline .
RelativeFilePath = /* slash-separated relative file path */ .
</code>
Пример
<code>ignore ./node_modules ignore ( static content/html ./third_party/javascript ) </code>
exclude директива
Директива exclude предотвращает загрузку версии модуля командой go.
Начиная с Go 1.16, если версия, на которую ссылается директива require в каком-либо файле go.mod, исключена директивой exclude в файле go.mod главного модуля, то такая зависимость игнорируется. Это может привести к тому, что команды, такие как go get и go mod tidy, добавят новые зависимости на более высокие версии в go.mod, с комментарием // indirect, если это уместно.
До Go 1.16, если исключённая версия ссылалась на require директиву, команда go выводила список доступных версий для модуля (как показано с помощью go list -m -versions), и загружала следующую более высокую версию, которая не была исключена. Это могло привести к недетерминированному выбору версии, поскольку следующая более высокая версия могла меняться со временем. При этом рассматривались как релизные, так и предрелизные версии, но псевдоверсии не учитывались. Если более высоких версий не было, команда go сообщала об ошибке.
Директивы exclude применяются только в файле go.mod главного модуля и игнорируются в других модулях. Подробнее см. в разделе Выбор минимальной версии.
<code>ExcludeDirective = "exclude" ( ExcludeSpec | "(" newline { ExcludeSpec } ")" newline ) .
ExcludeSpec = ModulePath Version newline .
</code>
Пример:
<code>exclude golang.org/x/net v1.2.3 exclude ( golang.org/x/crypto v1.4.5 golang.org/x/text v1.6.7 ) </code>
replace директива
Директива replace заменяет содержимое конкретной версии модуля или всех версий модуля на содержимое, находящееся в другом месте. Замена может быть указана либо с помощью другого пути и версии модуля, либо с помощью платформо-зависимого пути к файлу.
Если версия указана на левой стороне стрелки (=>), заменяется только эта конкретная версия модуля; другие версии будут доступны обычным образом. Если версия слева опущена, заменяются все версии модуля.
Если путь справа от стрелки является абсолютным или относительным (начинается с ./ или ../), он интерпретируется как локальный путь к корневой директории заменяемого модуля, который должен содержать файл go.mod. В этом случае версия замены должна быть опущена.
Если путь справа не является локальным, он должен быть корректным путём модуля. В этом случае требуется указание версии. Та же самая версия модуля не должна присутствовать в списке сборки.
Независимо от того, указывается ли замена с локальным путём или путём модуля, если у заменяемого модуля есть файл go.mod, его директива module должна соответствовать пути модуля, который он заменяет.
Директивы replace применяются только в файле go.mod главного модуля и игнорируются в других модулях. Подробнее см. в разделе Выбор минимальной версии.
Если имеется несколько главных модулей, применяются файлы go.mod всех главных модулей. Конфликтующие директивы replace между главными модулями запрещены и должны быть удалены или переопределены в replace в файле go.work.
Обратите внимание, что сама по себе директива replace не добавляет модуль в граф модулей. Также необходима require директива, ссылающаяся на заменённую версию модуля, либо в файле go.mod главного модуля, либо в файле go.mod зависимости. Директива replace не имеет эффекта, если версия модуля слева не требуется.
<code>ReplaceDirective = "replace" ( ReplaceSpec | "(" newline { ReplaceSpec } ")" newline ) .
ReplaceSpec = ModulePath [ Version ] "=>" FilePath newline
| ModulePath [ Version ] "=>" ModulePath Version newline .
FilePath = /* platform-specific relative or absolute file path */
</code>
Пример:
<code>replace golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5 replace ( golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5 golang.org/x/net => example.com/fork/net v1.4.5 golang.org/x/net v1.2.3 => ./fork/net golang.org/x/net => ./fork/net ) </code>
retract директива
Директива retract указывает, что версия или диапазон версий модуля, определённого в go.mod, не должен использоваться в зависимостях. Директива retract полезна, когда версия была опубликована преждевременно или была обнаружена серьёзная проблема после публикации версии. Возвращённые версии должны оставаться доступными в системах контроля версий и на прокси модулей, чтобы убедиться, что сборки, зависящие от них, не были сломаны. Слово retract заимствовано из академической литературы: возвращённая научная статья остаётся доступной, но имеет проблемы и не должна быть основой для будущих работ.
Когда версия модуля возвращается, пользователи не будут автоматически переходить на неё с использованием команд go get, go mod tidy или других команд. Сборки, зависящие от возвращённых версий, должны продолжать работать, но пользователи будут уведомлены об этих возвращениях при проверке обновлений с помощью go list -m -u или обновлении связанных модулей с помощью go get.
Чтобы вернуть версию, автор модуля должен добавить директиву retract в go.mod, а затем опубликовать новую версию, содержащую эту директиву. Новая версия должна быть выше других версий релиза или предрелиза; то есть, запрос версии @latest должен разрешаться в новую версию до того, как будут учтены возвращения. Команда go загружает и применяет возвращения из версии, показанной командой go list -m -retracted $modpath@latest (где $modpath — это путь к модулю).
Возвращённые версии скрыты из списка версий, выводимого командой go list -m -versions, если не используется флаг -retracted. Возвращённые версии исключаются при разрешении запросов версий, таких как @>=v1.2.3 или @latest.
Версия, содержащая возвращения, может возвращать саму себя. Если самая высокая версия релиза или предрелиза модуля возвращает саму себя, то запрос @latest разрешается в более низкую версию после исключения возвращённых версий.
Например, рассмотрим случай, когда автор модуля example.com/m случайно опубликовал версию v1.0.0. Чтобы предотвратить переход пользователей на v1.0.0, автор может добавить две директивы retract в go.mod, а затем пометить v1.0.1 возвращениями.
<code>retract ( v1.0.0 // Опубликовано по ошибке. v1.0.1 // Содержит только отмены. ) </code>
Когда пользователь запускает go get example.com/m@latest, команда go читает
отмены из v1.0.1, которая теперь является самой высокой версией. Поскольку обе
v1.0.0 и v1.0.1 отменены, команда go обновит (или понизит!) до следующей
наибольшей версии, возможно v0.9.5.
Директивы retract могут быть записаны либо с одной версией (например, v1.0.0),
либо с закрытым интервалом версий с верхней и нижней границей, разделёнными
[ и ] (например, [v1.1.0, v1.2.0]). Одиночная версия эквивалентна интервалу,
где верхняя и нижняя границы совпадают. Как и другие директивы, несколько
директив retract могут быть объединены в блок, ограниченный ( в конце строки и
) на отдельной строке.
Каждая директива retract должна иметь комментарий, объясняющий причину отмены,
хотя это не обязательно. Команда go может отображать комментарии с причинами в
предупреждениях об отменённых версиях и в выводе go list. Комментарий с причиной
может быть написан непосредственно над директивой retract (без пустой строки между
ними) или после неё на той же строке. Если комментарий появляется выше блока, он
применяется ко всем директивам retract внутри блока, у которых нет собственных
комментариев. Комментарий с причиной может занимать несколько строк.
<code>RetractDirective = "retract" ( RetractSpec | "(" newline { RetractSpec } ")" newline ) .
RetractSpec = ( Version | "[" Version "," Version "]" ) newline .
</code>
Примеры:
- Отмена всех версий между
v1.0.0иv1.9.9:
<code>retract v1.0.0 retract [v1.0.0, v1.9.9] retract ( v1.0.0 [v1.0.0, v1.9.9] ) </code>
- Возврат к неверсионному состоянию после преждевременной публикации версии
v1.0.0:
<code>retract [v0.0.0, v1.0.1] // предполагается, что v1.0.1 содержит эту отмену. </code>
- Удаление модуля, включая все псевдо-версии и тегированные версии:
<code>retract [v0.0.0-0, v0.15.2] // предполагается, что v0.15.2 содержит эту отмену. </code>
Директива retract была добавлена в Go 1.16. Go 1.15 и более ранние версии будут
сообщать об ошибке, если директива retract будет записана в файле go.mod
главного модуля, и игнорируют директивы retract в файлах
go.mod зависимостей.
Автоматические обновления
Большинство команд выводят ошибку, если в go.mod отсутствует информация или она
некорректно отражает действительность. Команды go get и
go mod tidy могут использоваться для исправления большинства
этих проблем. Кроме того, флаг -mod=mod может быть использован с большинством
команд, работающих с модулями (go build, go test и так далее), чтобы команда
go автоматически исправляла проблемы в go.mod и go.sum.
Например, рассмотрим следующий файл go.mod:
<code>module example.com/M go 1.23.0 require ( example.com/A v1 example.com/B v1.0.0 example.com/C v1.0.0 example.com/D v1.2.3 example.com/E dev ) exclude example.com/D v1.2.3 </code>
Обновление, запущенное с флагом -mod=mod, преобразует недженериковые идентификаторы версий в каноническую форму semver, так что v1 у пакета example.com/A становится v1.0.0, а dev у пакета example.com/E преобразуется в псевдо-версию последнего коммита в ветке dev, возможно v0.0.0-20180523231146-b3f5c0f6e5f1.
Обновление также изменяет требования, чтобы они учитывали исключения. Таким образом, требование к исключённой версии example.com/D v1.2.3 обновляется до использования следующей доступной версии пакета example.com/D, возможно v1.2.4 или v1.3.0.
Обновление удаляет избыточные или вводящие в заблуждение требования. Например, если example.com/A v1.0.0 сам требует example.com/B v1.2.0 и example.com/C v1.0.0, тогда требование example.com/B v1.0.0 в go.mod является вводящим в заблуждение (заменяется потребностями example.com/A в версии v1.2.0), а требование example.com/C v1.0.0 является избыточным (подразумевается из потребностей example.com/A к той же версии), поэтому оба будут удалены. Если основной модуль содержит пакеты, которые напрямую импортируют пакеты из example.com/B или example.com/C, то требования будут сохранены, но обновлены до используемых на самом деле версий.
Наконец, обновление приводит форматирование файла go.mod к каноническому виду, чтобы будущие механические изменения вызывали минимальные различия. Команда go не будет обновлять go.mod, если нужно изменить только форматирование.
Поскольку граф модулей определяет смысл инструкций импорта, любые команды, загружающие пакеты, также используют go.mod и могут обновлять его, включая go build, go get, go install, go list, go test, go mod tidy.
В Go 1.15 и более ранних версиях флаг -mod=mod был включён по умолчанию, поэтому обновления происходили автоматически. Начиная с Go 1.16, команда go ведёт себя так, как если бы был установлен флаг -mod=readonly: если необходимы какие-либо изменения в go.mod, команда go выводит ошибку и предлагает исправление.
Минимальный выбор версии (MVS)
Go использует алгоритм, называемый Минимальный выбор версии (MVS), для выбора набора версий модулей при сборке пакетов. MVS подробно описан в статье Minimal Version Selection Расса Кокса.
Концептуально, MVS работает с ориентированным графом модулей, задаваемым с помощью go.mod-файлов. Каждая вершина графа представляет собой версию модуля. Каждое ребро представляет минимально необходимую версию зависимости, указанную с помощью директивы require. Граф может быть изменён директивами exclude и replace в go.mod-файле(ях) основного модуля(ей) и директивами replace в файле go.work.
MVS формирует список сборки в качестве результата, то есть список версий модулей, используемых при сборке.
MVS начинает работу с главных модулей (особых вершин в графе, у которых нет версии) и обходит граф, отслеживая максимальную требуемую версию каждого модуля. По завершении обхода, максимальные требуемые версии составляют список сборки: это минимальные версии, удовлетворяющие всем требованиям.
Список сборки может быть просмотрен с помощью команды go list -m all. В отличие от других систем управления зависимостями, список сборки не сохраняется в файле «блокировки». MVS детерминирован, и список сборки не меняется при выходе новых версий зависимостей, поэтому MVS используется для его вычисления в начале каждой команды, поддерживающей работу с модулями.
Рассмотрим пример, изображённый на диаграмме ниже. Главный модуль требует модуль A в версии 1.2 или выше и модуль B в версии 1.2 или выше. A 1.2 и B 1.2 требуют соответственно C 1.3 и C 1.4. C 1.3 и C 1.4 оба требуют D 1.2.
MVS посещает и загружает файл go.mod для каждой из версий модулей, выделенных синим цветом. По завершении обхода графа MVS возвращает список сборки, содержащий выделенные версии: A 1.2, B 1.2, C 1.4 и D 1.2. Обратите внимание, что более высокие версии B и D доступны, но MVS не выбирает их, поскольку никто не требует их явно.
Замена
Содержимое модуля (включая его файл go.mod) может быть заменено с помощью replace-директивы в файле go.mod главного модуля или файла go.work рабочей области. replace-директива может применяться к конкретной версии модуля или ко всем версиям модуля.
Замены изменяют граф модулей, поскольку заменённый модуль может иметь другие зависимости, чем заменяемые версии.
Рассмотрим пример ниже, где C 1.4 был заменён на R. R зависит от D 1.3 вместо D 1.2, поэтому MVS возвращает список сборки, содержащий A 1.2, B 1.2, C 1.4 (заменён на R) и D 1.3.
Исключение
Модуль также может быть исключён на конкретных версиях с использованием exclude-директивы в файле go.mod главного модуля.
Исключения также изменяют граф модулей. Когда версия исключена, она удаляется из графа модулей, и требования к ней перенаправляются на следующую более высокую версию.
Рассмотрим пример ниже. C 1.3 было исключено. MVS будет действовать так, как если бы A 1.2 требовал C 1.4 (следующую более высокую версию) вместо C 1.3.
Обновления
Команда go get может использоваться для обновления набора модулей. Для выполнения обновления, команда go изменяет граф модулей перед запуском MVS, добавляя ребра от посещённых версий к обновлённым версиям.
Рассмотрим следующий пример. Модуль B может быть обновлён с 1.2 до 1.3, C может быть обновлён с 1.3 до 1.4, а D может быть обновлён с 1.2 до 1.3.
Обновления (и понижения) могут добавлять или удалять косвенные зависимости. В данном случае, E 1.1 и F 1.1 появляются в списке сборки после обновления, поскольку E 1.1 требуется модулем B 1.3.
Чтобы сохранить обновления, команда go обновляет требования в go.mod. Она изменит требование к B на версию 1.3. Также будут добавлены требования к C 1.4 и D 1.3 с комментариями // indirect, поскольку эти версии не были бы выбраны иначе.
Понижение версии
Команда go get также может использоваться для понижения версии набора модулей. Для выполнения понижения, команда go изменяет граф модулей, удаляя версии выше пониженных. Также удаляются версии других модулей, которые зависят от удалённых версий, поскольку они могут быть несовместимы с пониженными версиями своих зависимостей. Если основной модуль требует версию модуля, удалённую при понижении, то требование изменяется на предыдущую версию, которая не была удалена. Если предыдущая версия недоступна, требование удаляется.
Рассмотрим следующий пример. Предположим, что была найдена проблема с C 1.4, поэтому мы понижаем версию до C 1.3. C 1.4 удаляется из графа модулей. B 1.2 также удаляется, поскольку он требует C 1.4 или выше. Требование основного модуля к B изменяется на 1.1.
Команда go get также может полностью удалить зависимости, используя суффикс @none после аргумента. Это работает аналогично понижению. Все версии указанного модуля удаляются из графа модулей.
Сокращение графа модулей
Если основной модуль имеет go 1.17 или выше, то граф модулей, используемый для выбора минимальной версии, включает только непосредственные требования для каждого модуля зависимости, который указывает go 1.17 или выше в своём файле go.mod, если только эта версия модуля не требуется (транзитивно) какой-либо другой зависимостью с версией go 1.16 или ниже. (Транзитивные зависимости go 1.17 зависимостей удаляются из графа модулей.)
Поскольку файл go.mod с go 1.17 включает директиву require для каждой зависимости, необходимой для сборки любого пакета или теста в этом модуле, сокращённый граф модулей включает все зависимости, необходимые для go build или go test пакетов в любой зависимости, явно требуемой основным модулем. Модуль, который не нужен для сборки любого пакета или теста в данном модуле, не может повлиять на поведение во время выполнения его пакетов, поэтому зависимости, удалённые из графа модулей, могли бы только вызвать конфликт между иными несвязанными модулями.
Модули, требования к которым были отфильтрованы, по-прежнему отображаются в графе модулей и всё ещё сообщаются командой go list -m all: их выбранные версии известны и чётко определены, и пакеты могут быть загружены из этих модулей (например, как транзитивные зависимости тестов, загружаемых из других модулей). Однако, поскольку команда go не может легко определить, какие зависимости этих модулей удовлетворены, аргументы для go build и go test не могут включать пакеты из модулей, требования к которым были отфильтрованы. Команда go get повышет модуль, содержащий каждый указанный пакет, до явной зависимости, что позволяет вызвать go build или go test для этого пакета.
Поскольку Go 1.16 и более ранние версии не поддерживали отсечение графа модулей, полная транзитивная оболочка зависимостей — включая транзитивные зависимости go 1.17 — всё ещё включается для каждого модуля, указывающего go 1.16 или более низкую версию. (На версиях go 1.16 и ниже файл go.mod включает только прямые зависимости, поэтому для обеспечения включения всех косвенных зависимостей необходимо загрузить гораздо больший граф.)
Файл go.sum, записываемый командой go mod tidy для модуля по умолчанию, включает контрольные суммы, необходимые для версии Go на одну ниже указанной в его директиве go. Таким образом, модуль go 1.17 включает контрольные суммы, необходимые для полного графа модулей, загружаемого Go 1.16, но модуль go 1.18 будет включать только контрольные суммы, необходимые для отфильтрованного графа модулей, загружаемого Go 1.17. Флаг -compat может использоваться для переопределения версии по умолчанию (например, чтобы более агрессивно отфильтровать файл go.sum в модуле go 1.17).
См. документ с описанием архитектуры для получения дополнительных сведений.
Ленивая загрузка модулей
Более подробные требования, добавленные для отсечения графа модулей, также позволяют реализовать другую оптимизацию при работе внутри модуля. Если основной модуль имеет версию go 1.17 или выше, команда go избегает загрузки полного графа модулей до тех пор, пока он не будет нужен. Вместо этого она загружает только файл go.mod основного модуля, а затем пытается загрузить пакеты, которые должны быть собраны, используя только эти зависимости. Если пакет, который нужно импортировать (например, зависимость теста для пакета вне основного модуля), не найден среди этих зависимостей, тогда остальная часть графа модулей загружается по запросу.
Если все импортируемые пакеты можно найти без загрузки графа модулей, команда go затем загружает файлы go.mod только для модулей, содержащих эти пакеты, и проверяет их зависимости против требований основного модуля, чтобы убедиться, что они локально согласованы. (Несогласованность может возникнуть из-за слияний в системе контроля версий, ручных правок и изменений в модулях, которые были заменены с использованием локальных путей файловой системы.)
Рабочие пространства
Рабочее пространство — это коллекция модулей на диске, которые используются в качестве основных модулей при выполнении выбора минимальной версии (MVS).
Рабочее пространство может быть объявлено в файле go.work, который указывает относительные пути к каталогам модулей, входящих в рабочее пространство. Если файл go.work не существует, рабочее пространство состоит из единственного модуля, содержащего текущий каталог.
Большинство подкоманд go, работающих с модулями, действуют на набор модулей, определяемых текущим рабочим пространством.
go mod init, go mod why, go mod edit, go mod tidy, go mod vendor,
и go get всегда работают с одним главным модулем.
Команда определяет, находится ли она в контексте рабочего пространства, сначала проверяя переменную окружения GOWORK. Если GOWORK установлена в значение off, команда будет работать в контексте одного модуля. Если переменная пуста или не задана, команда будет искать файл go.work в текущем рабочем каталоге и затем в родительских каталогах. Если файл найден, команда будет работать в рабочем пространстве, определённом этим файлом; в противном случае, рабочее пространство будет включать только модуль, содержащий рабочий каталог.
Если GOWORK указывает на путь к существующему файлу, оканчивающемуся на .work, будет включён режим рабочего пространства. Любое другое значение считается ошибкой. Вы можете использовать команду go env GOWORK, чтобы определить, какой файл go.work использует команда go. go env GOWORK будет пустым, если команда go не находится в режиме рабочего пространства.
Файлы go.work
Рабочее пространство определяется текстовым файлом, закодированным в UTF-8 и названным go.work. Файл go.work ориентирован на строки. Каждая строка содержит одну директиву, состоящую из ключевого слова и аргументов. Например:
<code>go 1.23.0 use ./my/first/thing use ./my/second/thing replace example.com/bad/thing v1.4.5 => example.com/good/thing v1.4.5 </code>
Как и в файлах go.mod, ключевое слово может быть вынесено в начало смежных строк для создания блока.
<code>use ( ./my/first/thing ./my/second/thing ) </code>
Команда go предоставляет несколько подкоманд для работы с файлами go.work.
go work init создаёт новые файлы go.work. go work use добавляет каталоги модулей в файл go.work. go work edit выполняет низкоуровневые правки.
golang.org/x/mod/modfile
пакет может быть использован Go-программами для выполнения тех же изменений программно.
Команда go будет поддерживать файл go.work.sum, который отслеживает хэши, используемые в рабочей области, но не входящие в файлы go.sum коллекционных модулей рабочей области.
Как правило, не рекомендуется добавлять файлы go.work в системы контроля версий по следующим причинам:
- Зафиксированный файл
go.workможет переопределить собственный файлgo.workразработчика из родительского каталога, что приведёт к путанице, когда его директивыuseне будут применяться. - Зафиксированный файл
go.workможет заставить систему непрерывной интеграции (CI) выбирать и, соответственно, тестировать неверные версии зависимостей модуля. Системы CI обычно не должны использовать файлgo.work, чтобы они могли тестировать поведение модуля так, как оно будет использоваться при требовании другими модулями, где файлgo.workвнутри модуля не имеет никакого эффекта.
Тем не менее, существуют случаи, когда имеет смысл зафиксировать файл go.work. Например, если модули в репозитории разрабатываются исключительно совместно, но не вместе с внешними модулями, может не быть необходимости использовать другую комбинацию модулей в рабочей области. В этом случае автор модуля должен убедиться, что отдельные модули правильно протестированы и выпущены.
Лексические элементы
Лексические элементы в файлах go.work определяются точно так же, как и для файлов go.mod.
Грамматика
Синтаксис go.work задан ниже с использованием расширенной формы Бэкуса — Наура (EBNF). Подробности о синтаксисе EBNF можно найти в разделе «Нотация» в Спецификации языка Go.
<code>GoWork = { Directive } .
Directive = GoDirective |
ToolchainDirective |
UseDirective |
ReplaceDirective .
</code>
Переводы, идентификаторы и строки обозначены как newline, ident и string соответственно.
Пути модулей и версии обозначены как ModulePath и Version. Пути модулей и версии задаются точно так же, как и для файлов go.mod.
<code>ModulePath = ident | string . /* see restrictions above */ Version = ident | string . /* see restrictions above */ </code>
go директива
Директива go обязательна в корректном файле go.work. Версия должна быть корректной версией релиза Go: положительное целое число, за которым следует точка и неотрицательное целое число (например, 1.18, 1.19).
Директива go указывает версию инструментария go, с которым должен работать файл go.work. Если в формате файла go.work вносятся изменения, будущие версии инструментария будут интерпретировать файл согласно указанной версии.
Файл go.work может содержать не более одной директивы go.
<code>GoDirective = "go" GoVersion newline . GoVersion = string | ident . /* допустимая версия релиза; см. выше */ </code>
Пример:
<code>go 1.23.0 </code>
toolchain директива
Директива toolchain объявляет рекомендуемую версию инструментария Go для использования в рабочей области.
Она влияет только в том случае, если используемая по умолчанию версия инструментария старше рекомендуемой.
Для получения дополнительной информации см. "Инструментарии Go".
<code>ToolchainDirective = "toolchain" ToolchainName newline . ToolchainName = string | ident . /* допустимое имя инструментария; см. “Инструментарии Go” */ </code>
Пример:
<code>toolchain go1.21.0 </code>
godebug директива
Директива godebug объявляет одно настройка GODEBUG,
которая применяется при работе в этой рабочей области.
Синтаксис и эффект аналогичны директиве go.mod файла godebug.
Когда используется рабочая область, директивы godebug в файлах go.mod игнорируются.
use директива
Директива use добавляет модуль на диске в набор основных модулей в рабочей области.
Её аргумент — это относительный путь к каталогу, содержащему файл go.mod модуля.
Директива use не добавляет модули, содержащиеся в подкаталогах указанного каталога.
Такие модули могут быть добавлены отдельными директивами use, указывающими на каталоги их go.mod файлов.
<code>UseDirective = "use" ( UseSpec | "(" newline { UseSpec } ")" newline ) .
UseSpec = FilePath newline .
FilePath = /* платформенно-зависимый относительный или абсолютный путь к файлу */
</code>
Пример:
<code>use ./mymod // example.com/mymod use ( ../othermod ./subdir/thirdmod ) </code>
replace директива
Аналогично директиве replace в файле go.mod, директива replace в файле go.work заменяет содержимое определённой версии модуля или всех версий модуля содержимым, найденным в другом месте.
Подстановка с использованием шаблона в go.work переопределяет конкретную версию replace в файле go.mod.
Директивы replace в файлах go.work переопределяют любые замены того же модуля или версии модуля в модулях рабочей области.
<code>ReplaceDirective = "replace" ( ReplaceSpec | "(" newline { ReplaceSpec } ")" newline ) .
ReplaceSpec = ModulePath [ Version ] "=>" FilePath newline
| ModulePath [ Version ] "=>" ModulePath Version newline .
FilePath = /* платформенно-зависимый относительный или абсолютный путь к файлу */
</code>
Пример:
<code>replace golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5 replace ( golang.org/x/net v1.2.3 => example.com/fork/net v1.4.5 golang.org/x/net => example.com/fork/net v1.4.5 golang.org/x/net v1.2.3 => ./fork/net golang.org/x/net => ./fork/net ) </code>
Совместимость с репозиториями, не использующими модули
Чтобы обеспечить плавный переход с GOPATH на модули, команда go может
загружать и собирать пакеты в режиме, осведомленном о модулях, из репозиториев, которые еще не перешли на модули, добавляя файл go.mod.
Когда команда go загружает модуль в заданной версии напрямую
из репозитория, она ищет URL репозитория для пути модуля, сопоставляет
версию с ревизией внутри репозитория, а затем извлекает архив репозитория
в этой ревизии. Если путь модуля совпадает с
путем корневой директории репозитория, и корневая директория репозитория
не содержит файла go.mod, команда go синтезирует файл go.mod в кэше модулей,
содержащий директиву module и ничего больше. Поскольку синтезированные
файлы go.mod не содержат директив require для своих зависимостей,
другие модули, зависящие от них, могут потребовать дополнительных директив require
(с комментариями // indirect), чтобы убедиться, что каждая зависимость извлекается
в той же версии при каждой сборке.
Когда команда go загружает модуль из прокси, она загружает файл go.mod отдельно
от остального содержимого модуля. Прокси ожидается, что будет предоставлять синтезированный файл go.mod,
если оригинальный модуль не имел такого файла.
+incompatible версии
Модуль, выпущенный в основной версии 2 или выше, должен иметь соответствующий суффикс основной версии в пути модуля. Например, если модуль выпущен в версии v2.0.0, его путь должен иметь суффикс /v2. Это позволяет команде go рассматривать несколько основных версий проекта как отдельные модули, даже если они разрабатываются в одном и том же репозитории.
Требование к суффиксу основной версии было введено при добавлении поддержки модулей в команду go, и многие репозитории уже имели теги релизов с основной версией 2 или выше до этого. Чтобы сохранить совместимость с такими репозиториями, команда go добавляет суффикс +incompatible к версиям с основной версией 2 или выше, у которых нет файла go.mod. +incompatible указывает, что версия является частью того же модуля, что и версии с меньшими номерами основных версий; следовательно, команда go может автоматически обновляться до более высоких +incompatible версий, даже если это может сломать сборку.
Рассмотрим пример ниже:
<code>require example.com/m v4.1.2+incompatible </code>
Версия v4.1.2+incompatible обозначает тег семантической версии v4.1.2 в репозитории, который предоставляет модуль example.com/m. Модуль должен находиться в корневой директории репозитория (то есть путь к корню репозитория также должен быть example.com/m), и файл go.mod отсутствовать. Модуль может иметь версии с меньшими номерами основной версии, например, v1.5.2, и команда go может автоматически выполнить обновление до v4.1.2+incompatible с этих версий (см. выбор минимальной версии (MVS) для получения информации о том, как работают обновления).
Репозиторий, который перешёл на использование модулей после версии v2.0.0, обычно должен выпустить новую основную версию. В приведённом выше примере автор должен создать модуль с путём example.com/m/v5 и выпустить версию v5.0.0. Также автор должен обновить импорты пакетов в модуле, чтобы использовать префикс example.com/m/v5 вместо example.com/m. См. Go Modules: v2 and Beyond для более подробного примера.
Обратите внимание, что суффикс +incompatible не должен присутствовать в тегах репозитория; тег вида v4.1.2+incompatible будет проигнорирован. Суффикс появляется только в версиях, используемых командой go. См. Сопоставление версий с коммитами для получения подробной информации о различии между версиями и тегами.
Также обратите внимание, что суффикс +incompatible может появляться в псевдо-версиях. Например, v2.0.1-20200722182040-012345abcdef+incompatible может быть допустимой псевдо-версией.
Минимальная совместимость модулей
Модуль, выпущенный в основной версии 2 или выше, должен иметь суффикс основной версии в своём пути модуля. Модуль может или не может быть разработан в поддиректории основной версии внутри репозитория. Это имеет последствия для пакетов, которые импортируют пакеты внутри модуля при сборке в режиме GOPATH.
Обычно в режиме GOPATH пакет хранится в директории, соответствующей пути к корню репозитория, объединённому с его директорией внутри репозитория. Например, пакет в репозитории с корневым путём example.com/repo в поддиректории sub будет храниться в $GOPATH/src/example.com/repo/sub и будет импортироваться как example.com/repo/sub.
Для модуля с суффиксом основной версии можно было бы ожидать найти пакет example.com/repo/v2/sub в директории $GOPATH/src/example.com/repo/v2/sub. Это потребовало бы, чтобы модуль разрабатывался в поддиректории v2 репозитория. Команда go поддерживает это, но не требует этого (см. Сопоставление версий с коммитами).
Если модуль не разрабатывается в подкаталоге основной версии, то его каталог в GOPATH не будет содержать суффикса основной версии, и его пакеты можно будет импортировать без этого суффикса. В приведённом выше примере пакет будет находиться в каталоге $GOPATH/src/example.com/repo/sub и импортироваться как example.com/repo/sub.
Это создаёт проблему для пакетов, предназначенные для сборки как в режиме модулей, так и в режиме GOPATH: режим модулей требует суффикс, а режим GOPATH — нет.
Чтобы решить эту проблему, в Go 1.11 была добавлена минимальная совместимость модулей, а затем она была перенесена в Go 1.9.7 и 1.10.3. Когда путь импорта разрешается в каталог в режиме GOPATH:
- При разрешении импорта вида
$modpath/$vn/$dir, где:$modpath— это корректный путь модуля,$vn— это суффикс основной версии,$dir— это возможно пустой подкаталог,
- Если выполняются все следующие условия:
- Пакет
$modpath/$vn/$dirотсутствует в любом соответствующемvendor-каталоге. - Файл
go.modприсутствует в том же каталоге, что и импортирующий файл, или в любом родительском каталоге до корня$GOPATH/src, - Каталог
$GOPATH[i]/src/$modpath/$vn/$suffixне существует (для любого корня$GOPATH[i]), - Файл
$GOPATH[d]/src/$modpath/go.modсуществует (для какого-либо корня$GOPATH[d]) и объявляет путь модуля как$modpath/$vn,
- Пакет
- Тогда импорт
$modpath/$vn/$dirбудет разрешён в каталог$GOPATH[d]/src/$modpath/$dir.
Эти правила позволяют пакетам, которые были перенесены в модули, импортировать другие пакеты, также перенесённые в модули, даже при сборке в режиме GOPATH, если подкаталог основной версии не использовался.
Команды, поддерживающие работу с модулями
Большинство команд go могут работать в режиме с поддержкой модулей или режиме GOPATH. В режиме с поддержкой модулей команда go использует файлы go.mod для поиска версионированных зависимостей и обычно загружает пакеты из кэша модулей, скачивая модули при их отсутствии. В режиме GOPATH команда go игнорирует модули; она ищет зависимости в vendor-каталогах и в GOPATH.
Начиная с Go 1.16, режим с поддержкой модулей включён по умолчанию, независимо от наличия файла go.mod. В более ранних версиях режим с поддержкой модулей включался, если файл go.mod присутствовал в текущем каталоге или любом родительском каталоге.
Режим с поддержкой модулей может управляться с помощью переменной окружения GO111MODULE, которая может быть установлена в значения on, off или auto.
- Если установлено
GO111MODULE=off, командаgoигнорирует файлыgo.modи запускается в режимеGOPATH. - Если установлено
GO111MODULE=onили переменная не установлена, командаgoзапускается в модульном режиме, даже если файлgo.modотсутствует. Не все команды работают без файлаgo.mod: см. Команды модулей вне модуля. - Если установлено
GO111MODULE=auto, командаgoзапускается в модульном режиме, если файлgo.modприсутствует в текущем каталоге или любом родительском каталоге. В Go 1.15 и более ранних версиях это было поведением по умолчанию. Подкомандыgo modиgo installс запросом версии запускаются в модульном режиме, даже если файлgo.modотсутствует.
В модульном режиме GOPATH больше не определяет значение импортов во время сборки, но по-прежнему хранит загруженные зависимости (в GOPATH/pkg/mod; см. Кэш модулей) и установленные команды (в GOPATH/bin, если не задана переменная GOBIN).
Команды сборки
Все команды, которые загружают информацию о пакетах, работают в модульном режиме. Сюда входят:
go buildgo fixgo generatego installgo listgo rungo testgo vet
При запуске в модульном режиме эти команды используют файлы go.mod для интерпретации путей импортов, указанных в командной строке или написанных в исходных файлах Go. Эти команды принимают следующие флаги, общие для всех команд модулей.
- Флаг
-modконтролирует, может лиgo.modавтоматически обновляться, а также используется ли каталогvendor.-mod=modуказывает командеgoигнорировать каталогvendorи автоматически обновлятьgo.mod, например, когда импортируемый пакет не предоставляется никаким известным модулем.-mod=readonlyуказывает командеgoигнорировать каталогvendorи выводить ошибку, еслиgo.modтребует обновления.-mod=vendorуказывает командеgoиспользовать каталогvendor. В этом режиме командаgoне будет использовать сеть или кэш модулей.- По умолчанию, если
goверсия вgo.modравна1.14или выше и каталогvendorприсутствует, командаgoдействует так, как если бы был указан флаг-mod=vendor. В противном случае командаgoдействует так, как если бы был указан флаг-mod=readonly. - Команда
go getотклоняет этот флаг, поскольку целью команды является изменение зависимостей, что допускается только при использовании флага-mod=mod.
- Флаг
-modcacherwуказывает командеgoсоздавать новые каталоги в кэше модулей с правами на чтение и запись вместо того, чтобы делать их доступными только для чтения. При последовательном использовании этого флага (обычно путем установкиGOFLAGS=-modcacherwв окружении или выполненияgo env -w GOFLAGS=-modcacherw), кэш модулей может быть удален с помощью команд, таких какrm -r, без предварительного изменения прав. Командаgo clean -modcacheможет быть использована для удаления кэша модулей, независимо от того, использовался ли флаг-modcacherw. - Флаг
-modfile=file.modуказывает командеgoчитать (и, возможно, записывать) альтернативный файл вместоgo.modв корневом каталоге модуля. Имя файла должно заканчиваться на.mod. Файл с именемgo.modвсе еще должен присутствовать для определения корневого каталога модуля, но он не будет доступен. Когда указан флаг-modfile, также используется альтернативный файлgo.sum: его путь выводится из флага-modfileпутем удаления расширения.modи добавления.sum.
Vendoring
При использовании модулей команда go обычно удовлетворяет зависимости, скачивая модули из их источников в кэш модулей, а затем загружая пакеты из этих скачанных копий. Vendoring может быть использован для обеспечения совместимости со старыми версиями Go или для гарантии того, что все файлы, используемые для сборки, хранятся в одной файловой структуре.
Команда go mod vendor создаёт каталог с именем vendor в корневом каталоге основного модуля, содержащий копии всех пакетов, необходимых для сборки и тестирования пакетов в основном модуле. Пакеты, которые импортируются только тестами пакетов вне основного модуля, не включаются. Как и в случае с командами go mod tidy и другими командами модулей, ограничения сборки, кроме ignore, не учитываются при создании каталога vendor.
go mod vendor также создаёт файл vendor/modules.txt, который содержит список vendored пакетов и версии модулей, из которых они были скопированы. При включённом vendoring этот манифест используется как источник информации о версиях модулей, как это отображается командами go list -m и go version -m. Когда команда go читает файл vendor/modules.txt, она проверяет, что версии модулей согласуются с go.mod. Если go.mod был изменён с момента генерации vendor/modules.txt, команда go выдаст ошибку. Необходимо снова выполнить команду go mod vendor для обновления каталога vendor.
Если каталог vendor присутствует в корневом каталоге основного модуля, он будет использоваться автоматически, если go version в go.mod файле основного модуля равна 1.14 или выше. Чтобы явно включить vendoring, вызовите команду go с флагом -mod=vendor. Чтобы отключить vendoring, используйте флаг -mod=readonly или -mod=mod.
Когда vendoring включён, команды сборки, такие как go build и go test, загружают пакеты из каталога vendor, а не обращаются к сети или локальному кэшу модулей. Команда go list -m выводит информацию только о модулях, перечисленных в go.mod. Команды go mod, такие как go mod download и go mod tidy, не работают иначе при включённом vendoring и продолжают скачивать модули и обращаться к кэшу модулей. Команда go get также не работает иначе при включённом vendoring.
В отличие от менеджмента зависимостей в режиме GOPATH, команда go
игнорирует каталоги vendor в местах, отличных от корневого каталога основного модуля.
Кроме того, поскольку каталоги vendor в других модулях не используются, команда go не включает каталоги vendor при построении zip-файлов модулей (но см. известные ошибки
#31562 и
#37397).
go get
Использование:
<code>go get [-d] [-t] [-u] [build flags] [packages] </code>
Примеры:
<code># Обновить конкретный модуль. $ go get golang.org/x/net # Обновить модули, предоставляющие пакеты, импортированные в основной модуль. $ go get -u ./... # Обновить или понизить до конкретной версии модуля. $ go get golang.org/x/text@v0.3.2 # Обновить до коммита в ветке master модуля. $ go get golang.org/x/text@master # Удалить зависимость от модуля и понизить версии модулей, зависящих от него, # до версий, которые не требуют его. $ go get golang.org/x/text@none # Обновить минимально требуемую версию Go для основного модуля. $ go get go # Обновить рекомендуемый инструментарий Go, оставив минимальную версию Go без изменений. $ go get toolchain # Обновить до последнего патча рекомендуемого инструментария Go. $ go get toolchain@patch </code>
Команда go get обновляет зависимости модулей в файле go.mod для основного модуля, а затем собирает и устанавливает пакеты, указанные в командной строке.
Первым шагом является определение модулей, которые нужно обновить. Команда go get принимает список пакетов, шаблонов пакетов и путей модулей в качестве аргументов. Если указан аргумент пакета, go get обновляет модуль, предоставляющий этот пакет. Если указан шаблон пакета (например, all или путь с подстановочным знаком ...), go get раскрывает шаблон в набор пакетов, а затем обновляет модули, предоставляющие эти пакеты. Если аргумент указывает на модуль, но не на пакет (например, модуль golang.org/x/net не имеет пакета в своем корневом каталоге), go get обновит модуль, но не соберет пакет. Если аргументы не указаны, go get действует так, как если бы был указан аргумент . (пакет в текущем каталоге); это может использоваться вместе с флагом -u для обновления модулей, предоставляющих импортированные пакеты.
Каждый аргумент может включать суффикс запроса версии, указывающий желаемую версию, как в go get golang.org/x/text@v0.3.0. Суффикс запроса версии состоит из символа @, за которым следует запрос версии, который может указывать на конкретную версию (v0.3.0), префикс версии (v0.3), имя ветки или тега (master), ревизию (1234abcd) или одну из специальных команд latest, upgrade, patch или none. Если версия не указана, go get использует запрос @upgrade.
После того как go get определит свои аргументы до конкретных модулей и версий, go get добавит, изменит или удалит require директивы в файле go.mod основного модуля, чтобы обеспечить сохранение указанных версий модулей в будущем. Обратите внимание, что требуемые версии в файлах go.mod являются минимальными версиями и могут автоматически увеличиваться по мере добавления новых зависимостей. Подробнее о том, как выбираются версии и разрешаются конфликты, см. в разделе Выбор минимальной версии (MVS).
Другие модули могут быть обновлены, если модуль, указанный в командной строке, добавлен, обновлён или понижен, если новая версия указанного модуля требует других модулей в более высоких версиях. Например, предположим, что модуль example.com/a обновлён до версии v1.5.0, и эта версия требует модуль example.com/b в версии v1.2.0. Если модуль example.com/b в настоящее время требуется в версии v1.1.0, то команда go get example.com/a@v1.5.0 также обновит example.com/b до версии v1.2.0.
Другие модули могут быть понижены, если модуль, указанный в командной строке, понижается или удаляется. Продолжая приведённый выше пример, предположим, что модуль example.com/b понижается до версии v1.1.0. Модуль example.com/a также будет понижён до версии, которая требует example.com/b в версии v1.1.0 или ниже.
Требование к модулю может быть удалено с использованием суффикса версии @none. Это особый вид понижения. Модули, зависящие от удалённого модуля, будут понижены или удалены по мере необходимости. Требование к модулю может быть удалено даже если один или несколько его пакетов импортируются пакетами в основном модуле. В этом случае следующая команда сборки может добавить новое требование к модулю.
Если модуль необходим в двух различных версиях (указанных явно в аргументах командной строки или для удовлетворения обновлений и понижений), go get выдаст ошибку.
После того как go get выберет новый набор версий, он проверяет, не являются ли какие-либо недавно выбранные версии модулей или модули, предоставляющие пакеты, указанные в командной строке, отозванными или устаревшими. go get выводит предупреждение для каждой найденной отозванной версии или устаревшего модуля. Для проверки отзывов и устаревших модулей во всех зависимостях можно использовать команду go list -m -u all.
После того как go get обновит файл go.mod, он собирает пакеты, указанные в командной строке. Исполняемые файлы будут установлены в каталог, указанный переменной окружения GOBIN, которая по умолчанию равна $GOPATH/bin или $HOME/go/bin, если переменная окружения GOPATH не установлена.
go get поддерживает следующие флаги:
- Флаг
-dуказываетgo getне собирать и не устанавливать пакеты. При использовании-d,go getбудет управлять зависимостями только вgo.mod. Использованиеgo getбез-dдля сборки и установки пакетов устарело (начиная с Go 1.17). В Go 1.18 флаг-dвсегда будет включён. - Флаг
-uуказываетgo getобновлять модули, предоставляющие пакеты, импортируемые напрямую или косвенно пакетами, указанными в командной строке. Каждый модуль, выбранный с помощью-u, будет обновлён до своей последней версии, если только он уже не требуется в более высокой версии (предрелизной). - Флаг
-u=patch(не-u patch) также указываетgo getобновлять зависимости, ноgo getобновит каждую зависимость до последней патч-версии (аналогично запросу версии@patch). - Флаг
-tуказываетgo getучитывать модули, необходимые для сборки тестов пакетов, указанных в командной строке. При совместном использовании-tи-u,go getтакже обновит зависимости тестов. - Флаг
-insecureбольше не должен использоваться. Он позволяетgo getразрешать пользовательские пути импорта и получать данные из репозиториев и прокси модулей с использованием небезопасных схем, таких как HTTP. Переменная средыGOINSECUREсреды обеспечивает более точный контроль и должна использоваться вместо этого.
Начиная с Go 1.16, рекомендуемая команда для сборки и установки программ — go install. При использовании с суффиксом версии (например, @latest или @v1.4.6), go install собирает пакеты в режиме, осведомлённом о модулях, игнорируя файл go.mod в текущем каталоге или любом родительском каталоге, если такой имеется.
go get более сосредоточен на управлении требованиями в go.mod. Флаг -d устарел, и в Go 1.18 он всегда будет включён.
go install
Использование:
<code>go install [build flags] [packages] </code>
Примеры:
<code># Установить последнюю версию программы, # игнорируя go.mod в текущем каталоге (если он есть). $ go install golang.org/x/tools/gopls@latest # Установить конкретную версию программы. $ go install golang.org/x/tools/gopls@v0.6.4 # Установить программу в версии, выбранной модулем в текущем каталоге. $ go install golang.org/x/tools/gopls # Установить все программы в каталоге. $ go install ./cmd/... </code>
Команда go install собирает и устанавливает пакеты, названные путями в командной строке. Исполняемые файлы (main пакеты) устанавливаются в каталог, указанный переменной среды GOBIN, которая по умолчанию равна $GOPATH/bin или $HOME/go/bin, если переменная среды GOPATH не установлена. Исполняемые файлы в $GOROOT устанавливаются в $GOROOT/bin или $GOTOOLDIR вместо $GOBIN. Неисполняемые пакеты собираются и кэшируются, но не устанавливаются.
Начиная с Go 1.16, если аргументы содержат суффиксы версий (например, @latest или @v1.0.0), go install собирает пакеты в режиме, осведомленном о модулях, игнорируя файл go.mod в текущем каталоге или любом родительском каталоге, если такой существует. Это полезно для установки исполняемых файлов без влияния на зависимости основного модуля.
Чтобы устранить неоднозначность относительно того, какие версии модулей используются в сборке, аргументы должны соответствовать следующим ограничениям:
- Аргументы должны быть путями к пакетам или шаблонами пакетов (с подстановочными знаками "
..."). Они не должны быть стандартными пакетами (например,fmt), мета-шаблонами (std,cmd,all,work,tool) или относительными или абсолютными путями к файлам. - Все аргументы должны иметь одинаковый суффикс версии. Различные запросы не допускаются, даже если они ссылаются на одну и ту же версию.
- Все аргументы должны ссылаться на пакеты в одном и том же модуле на одной и той же версии.
- Аргументы путей к пакетам должны ссылаться на
mainпакеты. Шаблонные аргументы будут соответствовать толькоmainпакетам. - Никакой модуль не считается основным модулем.
- Если модуль, содержащий пакеты, указанные в командной строке, имеет файл
go.mod, он не должен содержать директив (replaceиexclude), которые привели бы к тому, что он был бы интерпретирован по-другому, если бы он был основным модулем. - Модуль не должен требовать более высокой версии сам себя.
- Каталоги vendor не используются ни в каком модуле. (Каталоги vendor не включены в zip-файлы модулей, поэтому
go installне скачивает их.)
- Если модуль, содержащий пакеты, указанные в командной строке, имеет файл
См. Запросы версий для поддерживаемого синтаксиса запросов версий. Go 1.15 и более ранние версии не поддерживали использование запросов версий с go install.
Если аргументы не содержат суффиксов версий, go install может работать в режиме, осведомленном о модулях, или в режиме GOPATH, в зависимости от переменной окружения GO111MODULE и наличия файла go.mod. См. Команды, осведомленные о модулях для получения дополнительных сведений. Если включен режим, осведомленный о модулях, go install выполняется в контексте основного модуля, который может отличаться от модуля, содержащего устанавливаемый пакет.
go list -m
Использование:
<code>go list -m [-u] [-retracted] [-versions] [list flags] [modules] </code>
Пример:
<code>$ go list -m all $ go list -m -versions example.com/m $ go list -m -json example.com/m@latest </code>
Флаг -m заставляет go list перечислять модули вместо пакетов. В этом режиме аргументы для go list могут быть модулями, шаблонами модулей (содержащими подстановочный знак ...), запросами версий или специальным шаблоном all, который соответствует всем модулям в списке сборки. Если аргументы не указаны, перечисляется основной модуль.
При перечислении модулей флаг -f по-прежнему указывает шаблон формата, применяемый к Go-структуре, но теперь к структуре Module:
<code>type Module struct {
Path string // путь к модулю
Version string // версия модуля
Versions []string // доступные версии модуля
Replace *Module // заменяет данный модуль
Time *time.Time // время создания версии
Update *Module // доступное обновление (с флагом -u)
Main bool // является ли этот модуль основным?
Indirect bool // модуль нужен только косвенно основным модулем
Dir string // каталог, содержащий локальную копию файлов, если есть
GoMod string // путь к файлу go.mod, описывающему модуль, если есть
GoVersion string // используемая в модуле версия Go
Retracted []string // информация о withdrawn версиях, если есть (с флагами -retracted или -u)
Deprecated string // сообщение об устаревшем модуле, если есть (с флагом -u)
Error *ModuleError // ошибка при загрузке модуля
}
type ModuleError struct {
Err string // сама ошибка
}
</code>
Вывод по умолчанию — это печать пути к модулю, а затем информации о версии и замене, если таковая имеется. Например, go list -m all может вывести:
<code>example.com/main/module golang.org/x/net v0.1.0 golang.org/x/text v0.3.0 => /tmp/text rsc.io/pdf v0.1.1 </code>
Структура Module имеет метод String, который форматирует эту строку вывода, поэтому формат по умолчанию эквивалентен -f '{{.String}}'.
Обратите внимание, что если модуль был заменён, его поле Replace описывает заменяющий модуль, а поле Dir устанавливается в каталог исходного кода заменяющего модуля, если он присутствует. (То есть, если Replace не равно nil, то Dir устанавливается в Replace.Dir, при этом доступ к исходному коду заменённого модуля отсутствует.)
Флаг -u добавляет информацию об доступных обновлениях. Если последняя версия заданного модуля новее текущей, list -u устанавливает поле Update модуля, содержащее информацию о более новой версии. list -u также выводит, является ли выбранная версия withdrawn и устаревшей. Метод String модуля показывает доступное обновление, форматируя более новую версию в скобках после текущей. Например, go list -m -u all может вывести:
<code>example.com/main/module golang.org/x/old v1.9.9 (deprecated) golang.org/x/net v0.1.0 (retracted) [v0.2.0] golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text rsc.io/pdf v0.1.1 [v0.1.2] </code>
(Для инструментов, go list -m -u -json all может быть удобнее для парсинга.)
Флаг -versions заставляет list установить поле Versions модуля в список всех известных версий этого модуля, упорядоченных согласно семантическому версионированию, от наименьшей к наибольшей. Флаг также изменяет формат вывода по умолчанию, чтобы отображать путь к модулю, за которым следуют версии, разделённые пробелами. Withdrawn версии исключаются из этого списка, если не указан флаг -retracted.
Флаг -retracted указывает команде list отображать отозванные версии в списке, выводимом с флагом -versions, а также учитывать отозванные версии при разрешении запросов версий. Например, команда go list -m -retracted example.com/m@latest отобразит самую высокую версию модуля example.com/m, включая предрелизную или релизную, даже если эта версия была отозвана. Директивы retract и устаревшие объявления загружаются из файла go.mod в указанной версии. Флаг -retracted был добавлен в Go 1.16.
Функция шаблона module принимает единственный строковый аргумент, который должен быть путём модуля или запросом, и возвращает указанный модуль в виде структуры Module. Если возникает ошибка, результат будет структурой Module с непустым полем Error.
go mod download
Использование:
<code>go mod download [-x] [-json] [-reuse=old.json] [modules] </code>
Пример:
<code>$ go mod download $ go mod download golang.org/x/mod@v0.2.0 </code>
Команда go mod download загружает указанные модули в кэш модулей. Аргументы могут быть путями модулей или шаблонами модулей, выбирающими зависимости основного модуля или запросами версий вида path@version. Если аргументы не указаны, команда download применяется ко всем зависимостям основного модуля.
Команда go автоматически загружает модули по мере необходимости во время обычного выполнения. Команда go mod download полезна в основном для предварительного заполнения кэша модулей или для загрузки данных, которые будут обслуживаться прокси модулей.
По умолчанию команда download ничего не выводит в стандартный поток вывода. Она выводит сообщения о ходе выполнения и ошибки в стандартный поток ошибок.
Флаг -json заставляет команду download выводить последовательность JSON-объектов в стандартный поток вывода, описывающих каждый загруженный модуль (или сбой), соответствующую следующей структуре Go:
<code>type Module struct {
Path string // путь модуля
Query string // запрос версии, соответствующий этой версии
Version string // версия модуля
Error string // ошибка загрузки модуля
Info string // абсолютный путь к кэшированному файлу .info
GoMod string // абсолютный путь к кэшированному файлу .mod
Zip string // абсолютный путь к кэшированному файлу .zip
Dir string // абсолютный путь к корневой директории исходного кода в кэше
Sum string // контрольная сумма для пути и версии (как в go.sum)
GoModSum string // контрольная сумма для go.mod (как в go.sum)
Origin any // происхождение модуля
Reuse bool // безопасно ли использовать информацию о старом модуле
}
</code>
Флаг -x заставляет команду download выводить выполняемые команды в стандартный поток ошибок.
Флаг -reuse принимает имя файла, содержащего вывод JSON предыдущего вызова команды go mod download -json. Команда go может использовать этот файл, чтобы определить, что модуль не изменился с момента предыдущего вызова, и избежать его повторной загрузки. Модули, которые не были загружены повторно, будут отмечены в новом выводе установкой поля Reuse в значение true. Обычно кэш модулей обеспечивает такое поведение автоматически; флаг -reuse может быть полезен на системах, где кэш модулей не сохраняется.
go mod edit
Использование:
<code>go mod edit [флаги редактирования] [-fmt|-print|-json] [go.mod] </code>
Пример:
<code># Добавить директиву replace. $ go mod edit -replace example.com/a@v1.0.0=./a # Удалить директиву replace. $ go mod edit -dropreplace example.com/a@v1.0.0 # Установить версию Go, добавить требование и распечатать файл # вместо записи его на диск. $ go mod edit -go=1.14 -require=example.com/m@v1.0.0 -print # Отформатировать файл go.mod. $ go mod edit -fmt # Отформатировать и распечатать другой .mod файл. $ go mod edit -print tools.mod # Распечатать JSON-представление файла go.mod. $ go mod edit -json </code>
Команда go mod edit предоставляет интерфейс командной строки для редактирования и форматирования файлов go.mod, который в основном используется инструментами и скриптами. Команда go mod edit читает только один файл go.mod; она не ищет информацию о других модулях. По умолчанию go mod edit читает и записывает файл go.mod основного модуля, но можно указать другой целевой файл после флагов редактирования.
Флаги редактирования задают последовательность операций редактирования.
- Флаг
-moduleизменяет путь модуля (строкуmoduleв файлеgo.mod). - Флаг
-go=versionустанавливает ожидаемую версию языка Go. - Флаги
-require=path@versionи-droprequire=pathдобавляют и удаляют требование к указанному пути и версии модуля. Обратите внимание, что флаг-requireпереопределяет любые существующие требования кpath. Эти флаги в основном предназначены для инструментов, понимающих граф модулей. Пользователи должны предпочитать использованиеgo get path@versionилиgo get path@none, которые вносят другие изменения вgo.modпо мере необходимости, чтобы удовлетворить ограничения, накладываемые другими модулями. См.go get. - Флаги
-exclude=path@versionи-dropexclude=path@versionдобавляют и удаляют исключение для указанного пути и версии модуля. Обратите внимание, что-exclude=path@versionне делает ничего, если такое исключение уже существует. - Флаг
-replace=old[@v]=new[@v]добавляет замену указанной пары пути и версии модуля. Если@vвold@vопущено, добавляется замена без версии слева, которая применяется ко всем версиям старого пути модуля. Если@vвnew@vопущено, новый путь должен быть корневой директорией локального модуля, а не путём модуля. Обратите внимание, что флаг-replaceпереопределяет любые избыточные замены дляold[@v], поэтому опускание@vприведёт к удалению замен для конкретных версий. - Флаг
-dropreplace=old[@v]удаляет замену указанной пары пути и версии модуля. Если указано@v, удаляется замена с указанной версией. Существующая замена без версии слева может всё ещё заменить модуль. Если@vопущено, удаляется замена без версии. - Флаги
-retract=versionи-dropretract=versionдобавляют и удаляют отмену (retraction) для указанной версии, которая может быть одной версией (например,v1.2.3) или интервалом (например,[v1.1.0,v1.2.0]). Обратите внимание, что флаг-retractне может добавить комментарий с объяснением для директивыretract. Рекомендуется добавлять такие комментарии, и они могут отображаться командамиgo list -m -uи другими. - Флаги
-tool=pathи-droptool=pathдобавляют и удаляют директивуtoolдля указанных путей. Обратите внимание, что это не добавит необходимые зависимости в граф сборки. Пользователи должны предпочитать использованиеgo get -tool pathдля добавления инструмента илиgo get -tool path@noneдля его удаления.
Флаги редактирования могут повторяться. Изменения применяются в порядке их указания.
go mod edit имеет дополнительные флаги, управляющие его выводом.
- Флаг
-fmtформатирует файлgo.modбез внесения других изменений. Это форматирование также неявно выполняется при любых других изменениях, которые используют или перезаписывают файлgo.mod. Флаг необходим только в том случае, если не указаны другие флаги, как вgo mod edit -fmt. - Флаг
-printвыводит окончательный файлgo.modв текстовом формате вместо записи его обратно на диск. - Флаг
-jsonвыводит окончательный файлgo.modв формате JSON вместо записи его обратно на диск в текстовом формате. Вывод в формате JSON соответствует следующим типам Go:
<code>type Module struct {
Path string
Version string
}
type GoMod struct {
Module ModPath
Go string
Require []Require
Exclude []Module
Replace []Replace
Retract []Retract
}
type ModPath struct {
Path string
Deprecated string
}
type Require struct {
Path string
Version string
Indirect bool
}
type Replace struct {
Old Module
New Module
}
type Retract struct {
Low string
High string
Rationale string
}
type Tool struct {
Path string
}
</code>
Обратите внимание, что это описывает только сам файл go.mod, а не другие модули, на которые ссылается проект косвенно. Для получения полного набора модулей, доступных для сборки, используйте go list -m -json all. См. go list -m.
Например, инструмент может получить файл go.mod в виде структуры данных, разбирая вывод команды go mod edit -json, а затем вносить изменения, вызывая go mod edit с флагами -require, -exclude и так далее.
Инструменты также могут использовать пакет
golang.org/x/mod/modfile
для разбора, редактирования и форматирования файлов go.mod.
go mod graph
Использование:
<code>go mod graph [-go=version] </code>
Команда go mod graph выводит граф требований модулей (с учётом замен) в текстовом виде. Например:
<code>example.com/main example.com/a@v1.1.0 example.com/main example.com/b@v1.2.0 example.com/a@v1.1.0 example.com/b@v1.1.1 example.com/a@v1.1.0 example.com/c@v1.3.0 example.com/b@v1.1.0 example.com/c@v1.1.0 example.com/b@v1.2.0 example.com/c@v1.2.0 </code>
Каждая вершина в графе модулей представляет конкретную версию модуля. Каждое ребро в графе представляет требование к минимальной версии зависимости.
go mod graph выводит рёбра графа, по одному на строку. Каждая строка содержит два поля, разделённых пробелом: версия модуля и одна из его зависимостей. Каждая версия модуля идентифицируется строкой вида path@version. Основной модуль не имеет суффикса @version, поскольку у него нет версии.
Флаг -go заставляет go mod graph отображать граф модулей, загруженный указанной версией Go, а не версией, указанной в go директиве в файле go.mod.
См. Выбор минимальной версии (MVS) для получения дополнительной информации о том, как выбираются версии. Также см. go list -m для печати выбранных версий и go mod why для понимания, почему модуль необходим.
go mod init
Использование:
<code>go mod init [module-path] </code>
Пример:
<code>go mod init go mod init example.com/m </code>
Команда go mod init инициализирует и записывает новый файл go.mod в текущем каталоге, тем самым создавая новый модуль, корнем которого является текущий каталог. Файл go.mod не должен уже существовать.
init принимает один необязательный аргумент — путь модуля нового модуля. См. Пути модулей для инструкций по выбору пути модуля. Если аргумент пути модуля опущен, init попытается вывести путь модуля, используя комментарии импорта в файлах .go и текущий каталог (если он находится в GOPATH).
go mod tidy
Использование:
<code>go mod tidy [-e] [-v] [-x] [-diff] [-go=version] [-compat=version] </code>
go mod tidy обеспечивает соответствие файла go.mod исходному коду в модуле. Она добавляет все необходимые требования к модулям, необходимые для сборки пакетов текущего модуля и его зависимостей, и удаляет требования к модулям, которые не предоставляют никаких соответствующих пакетов. Также она добавляет недостающие записи в go.sum и удаляет ненужные записи.
Флаг -e (добавлен в Go 1.16) заставляет go mod tidy продолжать работу несмотря на ошибки, возникшие при загрузке пакетов.
Флаг -v заставляет go mod tidy выводить информацию об удалённых модулях в стандартный поток ошибок.
Флаг -x заставляет go mod tidy выводить команды, которые выполняет tidy.
Флаг -diff заставляет go mod tidy не изменять go.mod или go.sum, а вместо этого выводить необходимые изменения в виде унифицированного diff. Команда завершается с ненулевым кодом, если diff не пуст.
go mod tidy работает, загружая все пакеты в главном модуле, все его инструменты и все пакеты, которые они импортируют, рекурсивно. Это включает пакеты, импортируемые тестами (включая тесты в других модулях). go mod tidy действует так, как если бы все build-теги были включены, поэтому он будет учитывать платформо-зависимые исходные файлы и файлы, требующие пользовательских build-тегов, даже если эти исходные файлы не строятся обычным образом. Единственное исключение: build-тег ignore не включён, поэтому файл с ограничением сборки // +build ignore не будет рассматриваться. Обратите внимание, что go mod tidy не будет учитывать пакеты в главном модуле в каталогах с именем testdata или с именами, начинающимися с . или _, если эти пакеты явно не импортируются другими пакетами.
Как только go mod tidy загрузит этот набор пакетов, он обеспечит наличие директивы require в основном модуле в файле go.mod для каждого модуля, который предоставляет один или несколько пакетов, или — если основной модуль находится на версии go 1.16 или ниже — является зависимостью другого требуемого модуля. go mod tidy добавит требование к последней версии каждого отсутствующего модуля (см. Запросы версий для определения понятия latest). go mod tidy удалит директивы require для модулей, которые не предоставляют никаких пакетов из описанного выше набора.
go mod tidy также может добавлять или удалять комментарии // indirect к директивам require. Комментарий // indirect обозначает модуль, который не предоставляет пакет, импортируемый пакетом в основном модуле. (См. require директиву для получения дополнительных сведений о том, когда добавляются // indirect зависимости и комментарии.)
Если установлена опция -go, go mod tidy обновит go директиву до указанной версии, включая или отключая сокращение графа модулей и ленивую загрузку модулей (а также добавляя или удаляя косвенные зависимости по мере необходимости) согласно этой версии.
По умолчанию go mod tidy проверяет, что выбранные версии модулей не изменяются при загрузке графа модулей Go версией, непосредственно предшествующей версии, указанной в директиве go. Проверяемая версия совместимости также может быть указана явно с помощью флага -compat.
go mod vendor
Использование:
<code>go mod vendor [-e] [-v] [-o] </code>
Команда go mod vendor создаёт каталог с именем vendor в корневом каталоге основного модуля, который содержит копии всех пакетов, необходимых для сборки и тестирования пакетов в основном модуле. Пакеты, которые импортируются только тестами пакетов вне основного модуля, не включаются. Как и в случае с go mod tidy и другими командами модулей, ограничения сборки, кроме ignore, не учитываются при создании каталога vendor.
Когда вендоринг включён, команда go будет загружать пакеты из каталога vendor вместо загрузки модулей из их источников в кэш модулей и использования загруженных копий. См. Вендоринг для получения дополнительной информации.
go mod vendor также создаёт файл vendor/modules.txt, который содержит список вендорных пакетов и версии модулей, из которых они были скопированы. При включённом вендоринге этот манифест используется как источник информации о версиях модулей, как показано командами go list -m и go version -m. Когда команда go читает файл vendor/modules.txt, она проверяет, что версии модулей согласуются с go.mod. Если go.mod был изменён после создания vendor/modules.txt, следует снова выполнить go mod vendor.
Обратите внимание, что команда go mod vendor удаляет каталог vendor, если он существует, перед тем как перестроить его. Локальные изменения не должны вноситься в пакеты, находящиеся в каталоге vendor. Команда go не проверяет, были ли пакеты в каталоге vendor изменены, но можно проверить целостность каталога vendor, выполнив команду go mod vendor и убедившись, что изменения не были внесены.
Флаг -e (добавлен в Go 1.16) заставляет go mod vendor продолжать выполнение, несмотря на ошибки, возникшие при загрузке пакетов.
Флаг -v заставляет go mod vendor выводить имена модулей и пакетов, помещённых в каталог vendor, в стандартный поток ошибок.
Флаг -o (добавлен в Go 1.18) заставляет go mod vendor вывести дерево каталога vendor в указанный каталог вместо использования vendor. Аргумент может быть как абсолютным путём, так и относительным от корня модуля.
go mod verify
Использование:
<code>go mod verify </code>
Команда go mod verify проверяет, не были ли зависимости основного модуля, хранящиеся в кэше модулей, изменены с момента их загрузки. Для выполнения этой проверки go mod verify вычисляет хэши каждого загруженного .zip-файла модуля и извлечённого каталога, а затем сравнивает эти хэши с хэшами, записанными при первоначальной загрузке модуля. Команда go mod verify проверяет каждый модуль из списка сборки (который может быть выведен с помощью go list -m all).
Если все модули остались неизменными, go mod verify выводит сообщение «all modules verified». В противном случае команда сообщает, какие модули были изменены, и завершается с ненулевым статусом.
Обратите внимание, что все команды, работающие с модулями, проверяют, соответствуют ли хэши в файле go.sum основного модуля хэшам, записанным для модулей, загруженных в кэш модулей. Если хэш отсутствует в go.sum (например, потому что модуль используется впервые), команда go проверяет его хэш с использованием базы данных хэшей (если только путь к модулю не совпадает с шаблоном GOPRIVATE или GONOSUMDB). Подробности см. в разделе Аутентификация модулей.
В отличие от этого, go mod verify проверяет, соответствуют ли хэши .zip-файлов модулей и их извлечённых каталогов хэшам, записанным в кэше модулей при первоначальной загрузке. Это полезно для обнаружения изменений файлов в кэше модулей после загрузки и проверки модуля. Команда go mod verify не загружает содержимое для модулей, отсутствующих в кэше, и не использует файлы go.sum для проверки содержимого модулей. Однако go mod verify может загружать файлы go.mod с целью выполнения минимального выбора версии. При этом она будет использовать go.sum для проверки этих файлов и может добавлять записи в go.sum для отсутствующих хэшей.
go mod why
Использование:
<code>go mod why [-m] [-vendor] packages... </code>
go mod why показывает кратчайший путь в графе импортов от основного модуля к
каждому из указанных пакетов.
Вывод представляет собой последовательность абзацев, по одному для каждого пакета или модуля, перечисленного в командной строке, разделённых пустыми строками. Каждый абзац начинается с комментарийной строки, начинающейся с #, указывающей целевой пакет или модуль. Последующие строки показывают путь через граф импортов, по одному пакету на строку. Если пакет или модуль не используется из основного модуля, абзац будет содержать единственную заключённую в скобки заметку, указывающую на это.
Например:
<code>$ go mod why golang.org/x/text/language golang.org/x/text/encoding # golang.org/x/text/language rsc.io/quote rsc.io/sampler golang.org/x/text/language # golang.org/x/text/encoding (main module does not need package golang.org/x/text/encoding) </code>
Флаг -m заставляет go mod why рассматривать свои аргументы как список модулей.
go mod why выведет путь к любому пакету в каждом из модулей. Обратите внимание, что
даже при использовании флага -m, go mod why запрашивает граф пакетов, а не
граф модулей, выводимый командой go mod graph.
Флаг -vendor заставляет go mod why игнорировать импорты в тестах пакетов
вне основного модуля (как это делает go mod vendor). По умолчанию,
go mod why рассматривает граф пакетов, соответствующих шаблону all. Этот флаг не имеет эффекта после Go 1.16 в модулях, которые объявляют go 1.16 или выше
(используя go директиву в go.mod), поскольку смысл
all изменился на совпадение с набором пакетов, соответствующих go mod vendor.
go version -m
Использование:
<code>go version [-m] [-v] [file ...] </code>
Пример:
<code># Print Go version used to build go. $ go version # Print Go version used to build a specific executable. $ go version ~/go/bin/gopls # Print Go version and module versions used to build a specific executable. $ go version -m ~/go/bin/gopls # Print Go version and module versions used to build executables in a directory. $ go version -m ~/go/bin/ </code>
go version сообщает версию Go, использованную для сборки каждого исполняемого файла, указанного в командной строке.
Если файлы не указаны в командной строке, go version выводит информацию о своей собственной версии.
Если указан каталог, go version рекурсивно обходит этот каталог, ищет распознанные исполняемые файлы Go и сообщает их версии. По умолчанию, go version не выводит неизвестные файлы, найденные при сканировании каталога. Флаг -v заставляет его выводить такие файлы.
Флаг -m заставляет команду go version выводить информацию о версии модуля, встроенную в исполняемый файл, если такая информация доступна. Для каждого исполняемого файла go version -m выводит таблицу с полями, разделёнными табуляцией, как показано ниже.
<code>$ go version -m ~/go/bin/goimports /home/jrgopher/go/bin/goimports: go1.14.3 path golang.org/x/tools/cmd/goimports mod golang.org/x/tools v0.0.0-20200518203908-8018eb2c26ba h1:0Lcy64USfQQL6GAJma8BdHCgeofcchQj+Z7j0SXYAzU= dep golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= dep golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= </code>
Формат таблицы может измениться в будущем. Эту же информацию можно получить с помощью функции
runtime/debug.ReadBuildInfo.
Смысл каждой строки в таблице определяется словом в первом столбце.
path: путь к пакетуmain, использованному для сборки исполняемого файла.mod: модуль, содержащий пакетmain. Столбцы представляют собой, соответственно, путь модуля, версию и контрольную сумму. Главный модуль имеет версию(devel)и не имеет контрольной суммы.dep: модуль, предоставивший один или несколько пакетов, включённых в исполняемый файл. Формат такой же, как уmod.=>: замену модуля, указанного в предыдущей строке. Если замена представляет собой локальную директорию, выводится только путь к ней (без версии и контрольной суммы). Если замена указывает на версию модуля, выводятся путь, версия и контрольная сумма, как в случае сmodиdep. Заменённый модуль не имеет контрольной суммы.
go clean -modcache
Использование:
<code>go clean [-modcache] </code>
Флаг -modcache заставляет команду go clean удалять весь
кэш модулей, включая распакованный исходный код версионированных зависимостей.
Обычно это лучший способ удалить кэш модулей. По умолчанию большинство файлов и директорий в кэше модулей имеют атрибуты только для чтения, чтобы тесты и редакторы не изменяли файлы после их
аутентификации. К сожалению, это приводит к тому, что команды вроде rm -r не работают, поскольку файлы не могут быть удалены без предварительного изменения прав доступа к родительским директориям.
Флаг -modcacherw (принимаемый командами go build и другими командами, работающими с модулями), заставляет новые директории в кэше модулей быть доступными для записи. Чтобы передать флаг -modcacherw всем командам, работающим с модулями, добавьте его в переменную GOFLAGS. GOFLAGS может быть установлена в окружении или с помощью команды go env -w. Например, команда ниже устанавливает её навсегда:
<code>go env -w GOFLAGS=-modcacherw </code>
Флаг -modcacherw следует использовать с осторожностью; разработчики должны быть внимательны и не вносить изменения в файлы кэша модулей. Для проверки соответствия файлов кэша хэшам из файла go.sum основного модуля может быть использована команда go mod verify.
Запросы версий
Несколько команд позволяют указать версию модуля с помощью запроса версии, который указывается после символа @ после пути модуля или пакета в командной строке.
Примеры:
<code>go get example.com/m@latest go mod download example.com/m@master go list -m -json example.com/m@e3702bed2 </code>
Запрос версии может быть одним из следующих вариантов:
- Полностью указанная семантическая версия, например
v1.2.3, которая выбирает конкретную версию. Синтаксис см. в разделе Версии. - Префикс семантической версии, например
v1илиv1.2, который выбирает самую высокую доступную версию с таким префиксом. - Сравнение семантической версии, например
<v1.2.3или>=v1.5.6, которое выбирает ближайшую доступную версию к целевой (для>и>=— наименьшая версия, для<и<=— наибольшая). - Идентификатор ревизии для базового репозитория исходного кода, например префикс хэша коммита, тег ревизии или имя ветки. Если ревизия помечена семантической версией, этот запрос выбирает именно эту версию. В противном случае, этот запрос выбирает псевдо-версию для соответствующего коммита. Обратите внимание, что ветки и теги с именами, совпадающими с другими запросами версий, не могут быть выбраны таким образом. Например, запрос
v2выбирает последнюю версию, начинающуюся сv2, а не ветку с именемv2. - Строка
latest, которая выбирает самую высокую доступную версию релиза. Если релизные версии отсутствуют,latestвыбирает самую высокую предрелизную версию. Если нет тегов версий,latestвыбирает псевдо-версию для коммита в самом конце основной ветки репозитория. - Строка
upgrade, которая аналогичнаlatest, но если модуль в настоящее время требуется в более высокой версии, чемlatestвыберет (например, предрелизная версия),upgradeвыберет текущую версию. - Строка
patch, которая выбирает последнюю доступную версию с теми же номерами мажорной и минорной версии, что и требуемая в данный момент. Если версия в данный момент не требуется,patchэквивалентнаlatest. Начиная с Go 1.16, командаgo getтребует наличия текущей версии при использованииpatch(но флаг-u=patchне требует этого).
За исключением запросов к конкретным именованным версиям или ревизиям, все запросы учитывают доступные версии, сообщаемые командой go list -m -versions (см. go list -m). Этот список содержит только тегированные версии, а не псевдо-версии.
Версии модулей, запрещённые директивами exclude в основном модуле в файле go.mod, не учитываются.
Версии, охваченные директивами retract в файле go.mod от последней версии того же модуля, также игнорируются, за исключением случаев, когда флаг -retracted используется с командой go list -m или при загрузке директив retract.
Релизные версии предпочитают предрелизные версии. Например, если доступны версии v1.2.2 и v1.2.3-pre, то запрос latest выберет v1.2.2, даже если v1.2.3-pre выше. Запрос <v1.2.4 также выберет v1.2.2, даже если v1.2.3-pre ближе к v1.2.4. Если ни релизная, ни предрелизная версия недоступна, запросы latest, upgrade и patch выберут псевдо-версию для коммита на вершине ветки по умолчанию репозитория. Другие запросы будут выводить ошибку.
Команды модулей вне модуля
Команды Go, осведомлённые о модулях, обычно выполняются в контексте основного модуля, определяемого файлом go.mod в рабочей директории или в родительской директории. Некоторые команды могут быть выполнены в режиме осведомлённости о модулях без наличия файла go.mod, но большинство команд работают иначе или выводят ошибку при отсутствии файла go.mod.
См. Команды, осведомлённые о модулях, для получения информации о включении и отключении режима осведомлённости о модулях.
| Команда | Поведение |
|---|---|
go buildgo docgo fixgo fmtgo generatego installgo listgo rungo testgo vet
|
Могут быть загружены, импортированы и собраны только пакеты из стандартной библиотеки и пакеты, указанные как файлы .go в командной строке. Пакеты из других модулей не могут быть собраны, поскольку нет места для записи требований модулей и обеспечения детерминированных сборок.
|
go get |
Пакеты и исполняемые файлы могут быть собраны и установлены обычным образом. Обратите внимание, что при запуске go get без файла go.mod не существует основного модуля, поэтому директивы replace и exclude не применяются.
|
go list -m |
Для большинства аргументов требуются явные запросы версий, за исключением случаев, когда используется флаг -versions.
|
go mod download |
Для большинства аргументов требуются явные запросы версий. |
go mod edit |
Требуется явный аргумент файла. |
go mod graphgo mod tidygo mod vendorgo mod verifygo mod why
|
Эти команды требуют наличия файла go.mod и будут выводить ошибку, если он отсутствует.
|
go work init
Использование:
<code>go work init [moddirs] </code>
Команда init инициализирует и записывает новый файл go.work в текущем каталоге, тем самым создавая новую рабочую среду в текущем каталоге.
Команда go work init может дополнительно принимать пути к модулям рабочей среды в качестве аргументов. Если аргументы не указаны, будет создана пустая рабочая среда без модулей.
Каждый путь аргумента добавляется в директиву use в файле go.work. Также будет указан текущий номер версии Go в файле go.work.
go work edit
Использование:
<code>go work edit [editing flags] [go.work] </code>
Команда go work edit предоставляет интерфейс командной строки для редактирования файла go.work, который используется в основном инструментами или скриптами. Эта команда только читает go.work; она не ищет информацию о модулях, участвующих в операции. Если файл не указан, команда edit ищет файл go.work в текущем каталоге и его родительских каталогах.
Флаги редактирования указывают последовательность операций редактирования.
- Флаг
-fmtформатирует файлgo.workбез внесения других изменений. Это форматирование также подразумевается при любых других изменениях, которые используют или перезаписывают файлgo.work. Этот флаг необходим только в том случае, если не указаны другие флаги, например, в командеgo work edit -fmt. - Флаги
-use=pathи-dropuse=pathдобавляют и удаляют директивуuseиз набора каталогов модулей в файлеgo.work. - Флаг
-replace=old[@v]=new[@v]добавляет замену заданной пары пути и версии модуля. Если@vвold@vопущен, добавляется замена без версии на левой стороне, которая применяется ко всем версиям старого пути модуля. Если@vвnew@vопущен, новый путь должен быть корневым каталогом локального модуля, а не путём модуля. Обратите внимание, что флаг-replaceпереопределяет любые избыточные замены дляold[@v], поэтому опускание@vприведёт к удалению существующих замен для конкретных версий. - Флаг
-dropreplace=old[@v]удаляет замену заданной пары пути и версии модуля. Если@vопущен, удаляется замена без версии на левой стороне. - Флаг
-go=versionустанавливает ожидаемую версию языка Go.
Флаги редактирования могут повторяться. Изменения применяются в порядке, в котором они указаны.
Команда go work edit имеет дополнительные флаги, управляющие её выводом:
- Флаг
-printвыводит окончательный файлgo.workв текстовом формате вместо записи его обратно вgo.mod. - Флаг
-jsonвыводит окончательный файлgo.workв формате JSON вместо записи его обратно вgo.mod. Вывод в формате JSON соответствует следующим типам Go:
<code>type Module struct {
Path string
Version string
}
type GoWork struct {
Go string
Directory []Directory
Replace []Replace
}
type Use struct {
Path string
ModulePath string
}
type Replace struct {
Old Module
New Module
}
</code>
go work use
Использование:
<code>go work use [-r] [moddirs] </code>
Команда go work use предоставляет интерфейс командной строки для добавления
каталогов, при необходимости рекурсивно, в файл go.work.
Директива use будет добавлена в файл go.work для каждого указанного в командной строке
каталога, если он существует на диске, или удалена из файла go.work, если он не существует на диске.
Флаг -r выполняет рекурсический поиск модулей в указанных каталогах, и команда use работает так, как будто каждый из этих каталогов был указан в качестве аргумента.
go work sync
Использование:
<code>go work sync </code>
Команда go work sync синхронизирует список сборки рабочей области обратно в
модули рабочей области.
Список сборки рабочей области — это множество версий всех (транзитивных) зависимостей модулей, используемых для сборки в рабочей области. Команда go work sync генерирует этот список сборки, используя алгоритм Minimal Version Selection (MVS),
а затем синхронизирует эти версии обратно в каждый из модулей, указанных в рабочей области (с директивами use).
После того как список сборки рабочей области вычислен, файл go.mod каждого модуля в рабочей области перезаписывается с зависимостями, соответствующими списку сборки рабочей области. Обратите внимание, что Minimal Version Selection
гарантирует, что версия каждого модуля в списке сборки всегда будет такой же или выше, чем версия в соответствующем модуле рабочей области.
Прокси модулей
GOPROXY протокол
Прокси модулей — это HTTP-сервер, который может отвечать на запросы GET
по указанным ниже путям. Запросы не содержат параметров запроса, и не требуются конкретные заголовки, поэтому даже сайт, предоставляющий данные из фиксированной файловой системы (включая URL вида file://), может быть прокси модулей.
Успешные HTTP-ответы должны иметь код состояния 200 (OK). Перенаправления (3xx) следуют. Ответы с кодами состояния 4xx и 5xx рассматриваются как ошибки. Коды ошибок 404 (Not Found) и 410 (Gone) указывают, что запрашиваемый модуль или версия недоступны на прокси, но могут быть найдены в другом месте. Ответы об ошибках должны иметь тип содержимого text/plain с кодировкой charset, равной utf-8 или us-ascii.
Команда go может быть настроена для обращения к прокси или серверам системы контроля версий с использованием переменной окружения GOPROXY, которая принимает список URL прокси. Список может включать ключевые слова direct или off (подробнее см. в разделе Переменные окружения). Элементы списка могут разделяться запятыми (,) или вертикальными чертами (|), что определяет поведение при ошибке. Если URL сопровождается запятой, команда go переходит к последующим источникам только после получения ответа 404 (Not Found) или 410 (Gone). Если URL сопровождается вертикальной чертой, команда go переходит к последующим источникам после любой ошибки, включая не-HTTP ошибки, такие как таймауты. Такое поведение обработки ошибок позволяет прокси действовать как контроллер для неизвестных модулей. Например, прокси может отвечать кодом 403 (Forbidden) для модулей, не входящих в список одобренных (см. Частный прокси для частных модулей).
В таблице ниже указаны запросы, на которые должен отвечать модульный прокси. Для каждого пути $base — это часть пути URL прокси, $module — это путь модуля, а $version — это версия. Например, если URL прокси — https://example.com/mod, а клиент запрашивает файл go.mod для модуля golang.org/x/text в версии v0.3.2, клиент отправит GET-запрос по адресу https://example.com/mod/golang.org/x/text/@v/v00.3.2.mod.
Чтобы избежать неоднозначности при работе с файловыми системами без учёта регистра, элементы $module и $version кодируются с учётом регистра: каждая заглавная буква заменяется на восклицательный знак, за которым следует соответствующая строчная буква. Это позволяет хранить модули example.com/M и example.com/m одновременно, поскольку первый будет закодирован как example.com/!m.
| Путь | Описание |
|---|---|
$base/$module/@v/list |
Возвращает список известных версий заданного модуля в виде обычного текста, по одной версии на строку. В этот список не должны входить псевдоверсии. |
$base/$module/@v/$version.info |
Возвращает метаданные о конкретной версии модуля в формате JSON. Ответ должен быть объектом JSON, соответствующим структуре данных Go, указанной ниже:
type Info struct {
Version string // строка версии
Time time.Time // время коммита
}
Поле
Поле В будущем могут быть добавлены дополнительные поля, поэтому другие имена зарезервированы. |
$base/$module/@v/$version.mod |
Возвращает файл go.mod для конкретной версии модуля. Если в модуле отсутствует файл go.mod в запрашиваемой версии, должен быть возвращён файл, содержащий только инструкцию module с указанным путём модуля. В противном случае должен быть возвращён исходный, неизменённый файл go.mod.
|
$base/$module/@v/$version.zip |
Возвращает zip-файл, содержащий содержимое конкретной версии модуля. Подробности о том, как должен быть отформатирован этот zip-файл, см. в разделе Zip-файлы модулей. |
$base/$module/@latest |
Возвращает метаданные о последней известной версии модуля в том же формате, что и
$base/$module/@v/$version.info. Последняя версия должна быть той, которую команда go должна использовать, если $base/$module/@v/list пуст или ни одна из перечисленных версий не подходит. Этот конечный пункт является необязательным, и модульные прокси не обязаны его реализовывать.
|
При разрешении последней версии модуля команда go запрашивает
$base/$module/@v/list, а затем, если подходящие версии не найдены,
$base/$module/@latest. Команда go предпочитает, в порядке убывания: семантически
самую высокую версию релиза, семантически самую высокую предрелизную версию и
хронологически самую новую псевдоверсию. В Go 1.12 и более ранних версиях команда
go рассматривала псевдоверсии в $base/$module/@v/list как предрелизные
версии, но это больше не так с Go 1.13.
Прокси модулей должен всегда предоставлять одинаковое содержимое для успешных
ответов на запросы $base/$module/$version.mod и $base/$module/$version.zip.
Это содержимое криптографически аутентифицируется
с использованием go.sum файлов и, по умолчанию,
базы данных контрольных сумм.
Команда go кэширует большинство скачиваемых ею данных из прокси модулей в
кэше модулей по пути $GOPATH/pkg/mod/cache/download. Даже при прямой загрузке
из систем управления версиями команда go синтезирует явные info,
mod и zip файлы и сохраняет их в этом каталоге, как если бы они были
загружены напрямую из прокси. Структура кэша совпадает со структурой URL прокси,
поэтому раздача $GOPATH/pkg/mod/cache/download по адресу (или копирование в)
https://example.com/proxy позволила бы пользователям получить доступ к кэшированным
версиям модулей, установив переменную окружения GOPROXY в значение
https://example.com/proxy.
Связь с прокси
Команда go может скачивать исходный код модулей и метаданные с прокси модулей.
Переменная окружения GOPROXY может быть использована для настройки
прокси, к которым команда go может подключаться, а также для указания,
может ли она напрямую общаться с системами управления версиями.
Скачанные данные модулей сохраняются в кэше модулей.
Команда go обращается к прокси только тогда, когда ей требуется информация,
отсутствующая в кэше.
Раздел GOPROXY протокол описывает запросы,
которые могут быть отправлены на сервер GOPROXY. Однако полезно также понимать,
когда команда go выполняет такие запросы. Например, go build следует
нижеприведённой процедуре:
- Вычисляет список сборки, читая
go.modфайлы и выполняя минимальный отбор версий (MVS). - Читает пакеты, указанные в командной строке, и пакеты, от которых они зависят.
- Если пакет не предоставляется ни одним из модулей в списке сборки, находит модуль,
который его предоставляет. Добавляет требование модуля к последней версии в
go.mod, и начинает всё заново. - Собирает пакеты после загрузки всех данных.
Когда команда go вычисляет список сборки, она загружает файл go.mod для каждого модуля в графе модулей. Если файл go.mod отсутствует в кэше, команда go загрузит его из прокси с использованием запроса $module/@v/$version.mod (где $module — это путь модуля, а $version — версия). Эти запросы можно протестировать с помощью инструмента, такого как curl. Например, команда ниже загружает файл go.mod для модуля golang.org/x/mod в версии v0.2.0:
<code>$ curl https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.mod module golang.org/x/mod go 1.12 require ( golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 ) </code>
Чтобы загрузить пакет, команда go требует исходный код модуля, который его предоставляет. Исходный код модулей распространяется в виде файлов .zip, которые извлекаются в кэш модулей. Если модуль .zip отсутствует в кэше, команда go загрузит его с использованием запроса $module/@v/$version.zip.
<code>$ curl -O https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.zip $ unzip -l v0.2.0.zip | head Archive: v0.2.0.zip Length Date Time Name --------- ---------- ----- ---- 1479 00-00-1980 00:00 golang.org/x/mod@v0.2.0/LICENSE 1303 00-00-1980 00:00 golang.org/x/mod@v0.2.0/PATENTS 559 00-00-1980 00:00 golang.org/x/mod@v0.2.0/README 21 00-00-1980 00:00 golang.org/x/mod@v0.2.0/codereview.cfg 214 00-00-1980 00:00 golang.org/x/mod@v0.2.0/go.mod 1476 00-00-1980 00:00 golang.org/x/mod@v0.2.0/go.sum 5224 00-00-1980 00:00 golang.org/x/mod@v0.2.0/gosumcheck/main.go </code>
Обратите внимание, что запросы .mod и .zip являются отдельными, даже если файлы go.mod обычно находятся внутри файлов .zip. Команда go может потребоваться загрузить файлы go.mod для множества различных модулей, и файлы .mod значительно меньше файлов .zip. Кроме того, если проект на Go не содержит файла go.mod, прокси будет предоставлять синтетический файл go.mod, который содержит только module директиву. Синтетические файлы go.mod генерируются командой go при загрузке из системы контроля версий.
Если команде go необходимо загрузить пакет, который не предоставляется никаким модулем из списка сборки, она попытается найти новый модуль, который его предоставляет. Раздел Разрешение пакета в модуль описывает этот процесс. Вкратце, команда go запрашивает информацию о последней версии каждого пути модуля, который может содержать пакет. Например, для пакета golang.org/x/net/html команда go попытается найти последние версии модулей golang.org/x/net/html, golang.org/x/net, golang.org/x/ и golang.org. Только модуль golang.org/x/net действительно существует и предоставляет этот пакет, поэтому команда go использует последнюю версию этого модуля. Если более одного модуля предоставляет пакет, команда go выберет модуль с самым длинным путем.
Когда команда go запрашивает последнюю версию модуля, она сначала отправляет запрос на $module/@v/list. Если список пуст или ни одна из возвращённых версий не может быть использована, она отправляет запрос на $module/@latest. Как только версия выбрана, команда go отправляет запрос $module/@v/$version.info для получения метаданных. Затем она может отправить запросы $module/@v/$version.mod и $module/@v/$version.zip для загрузки файла go.mod и исходного кода.
<code>$ curl https://proxy.golang.org/golang.org/x/mod/@v/list
v0.1.0
v0.2.0
$ curl https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.info
{"Version":"v0.2.0","Time":"2020-01-02T17:33:45Z"}
</code>
После загрузки файла .mod или .zip, команда go вычисляет криптографическую хеш-функцию и проверяет, соответствует ли она хешу в основном модуле в файле go.sum. Если хеш отсутствует в go.sum, по умолчанию команда go извлекает его из базы данных хешей. Если вычисленный хеш не совпадает, команда go сообщает об ошибке безопасности и не устанавливает файл в кэш модулей. Переменные окружения GOPRIVATE и GONOSUMDB могут быть использованы для отключения запросов к базе данных хешей для определённых модулей. Также переменная окружения GOSUMDB может быть установлена в значение off, чтобы полностью отключить запросы к базе данных хешей. Подробнее см. в разделе Authenticating modules (Аутентификация модулей). Обратите внимание, что списки версий и метаданные версий, возвращаемые для запросов .info, не аутентифицируются и могут изменяться со временем.
Предоставление модулей напрямую через прокси
Большинство модулей разрабатываются и предоставляются из репозитория системы управления версиями. В прямом режиме команда go загружает такой модуль с помощью инструмента системы управления версиями (см. Системы управления версиями). Также возможно предоставление модуля напрямую через прокси-сервер модулей. Это полезно для организаций, которые хотят предоставлять модули без раскрытия серверов системы управления версиями, а также для организаций, использующих системы управления версиями, которые не поддерживаются командой go.
Когда команда go загружает модуль в прямом режиме, она сначала ищет URL сервера модуля с помощью HTTP GET-запроса, основанного на пути модуля. Она ищет тег <meta> с именем go-import в HTML-ответе. Содержимое тега должно содержать корневой путь репозитория, систему управления версиями и URL, разделённые пробелами. Подробнее см. в разделе Finding a repository for a module path (Поиск репозитория по пути модуля).
Если система управления версиями — mod, команда go загружает модуль по указанному URL с использованием GOPROXY протокола.
Например, предположим, что команда go пытается загрузить модуль
example.com/gopher в версии v1.0.0. Она отправляет запрос на
https://example.com/gopher?go-get=1. Сервер отвечает HTML-документом,
содержащим тег:
<code><meta name="go-import" content="example.com/gopher mod https://modproxy.example.com"> </code>
На основе этого ответа команда go загружает модуль, отправляя запросы к
https://modproxy.example.com/example.com/gopher/@v/v1.0.0.info,
v1.0.0.mod и v1.0.0.zip.
Обратите внимание, что модули, которые предоставляются напрямую через прокси, не могут быть загружены с помощью
go get в режиме GOPATH.
Системы управления версиями
Команда go может загружать исходный код модуля и метаданные непосредственно из репозитория системы управления версиями. Загрузка модуля через
прокси обычно происходит быстрее, но подключение напрямую к репозиторию необходимо, если прокси недоступен или если репозиторий модуля недоступен для прокси (что часто бывает с частными
репозиториями). Поддерживаются Git, Subversion, Mercurial, Bazaar и Fossil. Инструмент системы управления версиями должен быть установлен в каталоге, находящемся в переменной PATH, чтобы команда
go могла его использовать.
Чтобы загружать определённые модули из исходных репозиториев вместо прокси, установите переменные среды
GOPRIVATE или GONOPROXY. Чтобы настроить команду go на загрузку всех модулей напрямую из исходных репозиториев, установите GOPROXY в значение
direct. Дополнительную информацию см. в разделе Переменные среды.
Поиск репозитория для пути модуля
Когда команда go загружает модуль в режиме direct, она начинает с поиска репозитория, содержащего модуль.
Если путь модуля содержит квалификатор системы управления версиями (один из .bzr, .fossil, .git, .hg,
.svn) в конце компонента пути, команда go будет использовать всё, что до этого квалификатора, как URL репозитория. Например, для модуля
example.com/foo.git/bar, команда go загрузит репозиторий по адресу
example.com/foo с использованием git, ожидая найти модуль в подкаталоге bar. Команда go попытается угадать используемый протокол, основываясь на протоколах, поддерживаемых системой управления версиями.
Если путь модуля не содержит квалификатора, команда go отправляет HTTP-запрос GET к URL, полученному из пути модуля с добавлением строки запроса ?go-get=1. Например, для модуля
golang.org/x/mod, команда go может отправить следующие запросы:
<code>https://golang.org/x/mod?go-get=1 (предпочтительный) http://golang.org/x/mod?go-get=1 (резервный, только при установленной GOINSECURE) </code>
Команда go следует за перенаправлениями, но игнорирует коды состояния ответа, поэтому сервер может отвечать кодом 404 или любым другим кодом ошибки. Переменная окружения GOINSECURE может быть установлена для разрешения возврата и перенаправлений на незашифрованный HTTP для определённых модулей.
Сервер должен отвечать HTML-документом, содержащим тег <meta> в секции <head> документа. Тег <meta> должен находиться в начале документа, чтобы избежать путаницы с ограниченным парсером команды go. В частности, он должен быть указан до любого необработанного JavaScript или CSS. Тег <meta> должен иметь следующий формат:
<code><meta name="go-import" content="root-path vcs repo-url [subdirectory]"> </code>
root-path — это путь к корневой директории репозитория, часть пути модуля, соответствующая корневой директории репозитория, или subdirectory, если указан и используется Go 1.25 или новее (см. раздел о subdirectory ниже). Он должен быть префиксом или точным совпадением запрашиваемого пути модуля. Если это не точное совпадение, будет сделан дополнительный запрос для префикса, чтобы проверить соответствие тегов <meta>.
vcs — это система управления версиями. Она должна быть одним из инструментов, перечисленных в таблице ниже, или ключевым словом mod, которое указывает команде go загрузить модуль по указанному URL с использованием GOPROXY-протокола. Подробности смотрите в разделе Предоставление модулей напрямую через прокси.
repo-url — это URL репозитория. Если URL не содержит схему (либо потому, что путь модуля содержит квалификатор VCS, либо потому, что тег <meta> не содержит схемы), команда go попробует каждую поддерживаемую систему управления версиями. Например, для Git команда go попробует https://, а затем git+ssh://. Небезопасные протоколы (например, http:// и git://) могут использоваться только в том случае, если путь модуля совпадает с шаблоном, заданным переменной окружения GOINSECURE.
subdirectory, если указан, — это поддиректория репозитория, разделённая косой чертой, соответствующая root-path, и переопределяет стандартное значение — корневую директорию репозитория. Теги метаданных go-import, содержащие subdirectory, распознаются только в Go 1.25 и новее. Попытки загрузки модулей в более ранних версиях Go проигнорируют тег метаданных и приведут к ошибке разрешения, если модуль не может быть найден в других местах.
| Название | Команда | Значение по умолчанию в GOVCS | Безопасные схемы |
|---|---|---|---|
| Bazaar | bzr |
Только приватные | https, bzr+ssh |
| Fossil | fossil |
Только приватные | https |
| Git | git |
Публичные и приватные | https, git+ssh, ssh |
| Mercurial | hg |
Публичные и приватные | https, ssh |
| Subversion | svn |
Только приватные | https, svn+ssh |
В качестве примера рассмотрим пакет golang.org/x/mod. Команда go отправляет запрос на адрес https://golang.org/x/mod?go-get=1. Сервер отвечает HTML-документом, содержащим тег:
<code><meta name="go-import" content="golang.org/x/mod git https://go.googlesource.com/mod"> </code>
Из этого ответа команда go использует Git-репозиторий по удалённому адресу https://go.googlesource.com/mod.
Сервисы хостинга, такие как GitHub, и другие популярные платформы, отвечают на запросы с параметром ?go-get=1 для всех репозиториев, поэтому обычно не требуется дополнительная настройка сервера для модулей, размещённых на таких сайтах.
После того как будет найден URL репозитория, команда go клонирует репозиторий в кэш модулей. В общем случае команда go старается избегать загрузки ненужных данных из репозитория. Однако используемые команды могут отличаться в зависимости от системы управления версиями и со временем могут меняться. Для Git команда go может перечислить большинство доступных версий без загрузки коммитов. Обычно она загружает коммиты, не скачивая предшествующие коммиты, но иногда это необходимо.
Сопоставление версий с коммитами
Команда go может извлечь модуль внутри репозитория по конкретной канонической версии, например v1.2.3, v2.4.0-beta или v3.0.0+incompatible. Каждая версия модуля должна иметь семантический тег версии внутри репозитория, который указывает, какой ревизион должен быть извлечён для заданной версии.
Если модуль определён в корневой директории репозитория или в поддиректории, соответствующей мажорной версии, то имя каждого тега версии совпадает с соответствующей версией. Например, модуль golang.org/x/text определён в корневой директории его репозитория, поэтому версия v0.3.2 имеет тег v0.3.2 в этом репозитории. Это справедливо для большинства модулей.
Если модуль определён в поддиректории внутри репозитория, то есть часть пути модуля, обозначающая поддиректорию модуля, не пуста, то каждое имя тега должно начинаться с поддиректории модуля, за которой следует символ "/". Например, модуль golang.org/x/tools/gopls определён в поддиректории gopls репозитория с корневым путём golang.org/x/tools. Версия v0.4.0 этого модуля должна иметь тег с именем gopls/v0.4.0 в этом репозитории.
Мажорное число семантического тега версии должно соответствовать суффиксу мажорной версии пути модуля (если он есть). Например, тег v1.0.0 может принадлежать модулю example.com/mod, но не модулю example.com/mod/v2, который должен иметь теги вроде v2.0.0.
Тег с мажорной версией v2 или выше может принадлежать модулю без суффикса мажорной версии, если отсутствует файл go.mod и модуль находится в корневой директории репозитория. Такая версия обозначается суффиксом +incompatible. Сам тег версии не должен содержать этот суффикс. См. Совместимость с неподдерживаемыми модулями репозиториями.
Как только тег создан, он не должен быть удален или изменен на другую версию. Версии аутентифицируются, чтобы обеспечить безопасную и воспроизводимую сборку. Если тег изменяется, клиенты могут столкнуться с ошибкой безопасности при его загрузке. Даже после удаления тега его содержимое может оставаться доступным на прокси модулей.
Сопоставление псевдоверсий с коммитами
Команда go может извлечь модуль внутри репозитория в определенной версии, закодированной как псевдоверсия, например, v1.3.2-0.20191109021931-daa7c04131f5.
Последние 12 символов псевдоверсии (daa7c04131f5 в примере выше) обозначают ревизию в репозитории для извлечения. Значение этого зависит от системы управления версиями. Для Git и Mercurial это префикс хэша коммита. Для Subversion это нулированное число ревизии.
Перед извлечением коммита команда go проверяет, что метка времени (20191109021931 выше) соответствует дате коммита. Также проверяется, что базовая версия (v1.3.1, версия перед v1.3.2 в примере выше) соответствует семантическому тегу версии, который является предком коммита. Эти проверки обеспечивают, что авторы модулей имеют полный контроль над тем, как псевдоверсии сравниваются с другими опубликованными версиями.
Дополнительную информацию см. в разделе Псевдоверсии.
Сопоставление веток и коммитов с версиями
Модуль может быть извлечен в определенной ветке, теге или ревизии с использованием запроса версии.
<code>go get example.com/mod@master </code>
Команда go преобразует эти имена в канонические версии, которые можно использовать с минимальным выбором версий (MVS). MVS зависит от возможности однозначно упорядочить версии. Имена веток и ревизии нельзя надежно сравнивать со временем, поскольку они зависят от структуры репозитория, которая может изменяться.
Если ревизия помечена одним или несколькими семантическими тегами версий, такими как v1.2.3, будет использован тег с наибольшей допустимой версией. Команда go учитывает только семантические теги версий, которые могут принадлежать целевому модулю; например, тег v1.5.2 не будет рассматриваться для example.com/mod/v2, поскольку мажорная версия не соответствует суффиксу пути модуля.
Если ревизия не помечена допустимым семантическим тегом версии, команда go сгенерирует псевдоверсию. Если у ревизии есть предки с допустимыми семантическими тегами версий, будет использована наибольшая из них в качестве базовой псевдоверсии. См. Псевдоверсии.
Каталоги модулей внутри репозитория
Как только репозиторий модуля был проверен на конкретной версии, команда go должна определить каталог, содержащий файл go.mod модуля (корневой каталог модуля).
Напомним, что путь модуля состоит из трёх частей: путь корневого каталога репозитория (соответствующий корневому каталогу репозитория), подкаталог модуля и суффикс основной версии (только для модулей, выпущенных с версией v2 или выше).
Для большинства модулей путь модуля совпадает с путём корневого каталога репозитория, поэтому корневой каталог модуля совпадает с корневым каталогом репозитория.
Модули иногда определяются в подкаталогах репозитория. Это обычно делается для больших репозиториев с несколькими компонентами, которые необходимо выпускать и версионировать независимо. Такой модуль ожидается быть найденным в подкаталоге, соответствующем части пути модуля после корневого пути репозитория. Например, предположим, что модуль example.com/monorepo/foo/bar находится в репозитории с корневым путём example.com/monorepo. Файл go.mod этого модуля должен находиться в подкаталоге foo/bar.
Если модуль выпускается с основной версией v2 или выше, его путь должен иметь суффикс основной версии. Модуль с суффиксом основной версии может быть определён в одном из двух подкаталогов: с суффиксом и без него. Например, предположим, что новая версия вышеуказанного модуля выпускается с путём example.com/monorepo/foo/bar/v2. Файл go.mod этого модуля может находиться либо в foo/bar, либо в foo/bar/v2.
Подкаталоги с суффиксом основной версии являются подкаталогами основной версии. Они могут использоваться для разработки нескольких основных версий модуля в рамках одной ветки. Это может быть необязательно, если разработка нескольких основных версий ведётся в отдельных ветках. Однако подкаталоги основной версии обладают важным свойством: в режиме GOPATH пути импорта пакетов точно совпадают с каталогами под GOPATH/src. Команда go обеспечивает минимальную совместимость модулей в режиме GOPATH (см. Совместимость с неподдерживаемыми модулями репозиториями), поэтому подкаталоги основной версии не всегда необходимы для совместимости с проектами, созданными в режиме GOPATH. Однако более старые инструменты, которые не поддерживают минимальную совместимость модулей, могут испытывать проблемы.
Как только команда go найдёт корневой каталог модуля, она создаёт .zip-файл содержимого каталога, а затем распаковывает .zip-файл в кэш модулей. См. Ограничения размера и пути файлов для получения подробной информации о том, какие файлы могут быть включены в .zip-файл. Содержимое .zip-файла аутентифицируется перед распаковкой в кэш модулей так же, как если бы .zip-файл был загружен с прокси.
Файлы модулей в формате zip не включают содержимое каталогов vendor или любых вложенных модулей (подкаталогов, содержащих файлы go.mod). Это означает, что модуль должен быть осторожен и не ссылаться на файлы вне своего каталога или в других модулях. Например, шаблоны //go:embed не должны соответствовать файлам вложенных модулей. Это поведение может служить полезным обходным решением в ситуациях, когда файлы не должны быть включены в модуль. Например, если в репозитории есть большие файлы, закоммиченные в каталог testdata, автор модуля может добавить пустой файл go.mod в testdata, чтобы пользователи не скачивали эти файлы. Конечно, это может снизить покрытие для пользователей, тестирующих свои зависимости.
Особый случай для файлов LICENSE
Когда команда go создаёт файл .zip для модуля, который находится не в корневом каталоге репозитория, если у модуля нет файла с именем LICENSE в его корневом каталоге (рядом с go.mod), команда go скопирует файл с именем LICENSE из корневого каталога репозитория, если он присутствует в той же ревизии.
Этот специальный случай позволяет одному и тому же файлу LICENSE применяться ко всем модулям внутри репозитория. Это относится только к файлам с именем LICENSE, без расширений, таких как .txt. К сожалению, это нельзя расширить без нарушения криптографических сумм существующих модулей; см. Аутентификация модулей. Другие инструменты и веб-сайты, такие как pkg.go.dev, могут распознавать файлы с другими именами.
Также обратите внимание, что команда go не включает символические ссылки при создании модулей в формате .zip; см. Ограничения размера и пути файлов. Следовательно, если в репозитории нет файла LICENSE в его корневом каталоге, авторы могут вместо этого создать копии файлов лицензий в модулях, определённых в подкаталогах, чтобы убедиться, что эти файлы будут включены в файлы .zip модулей.
Управление инструментами системы контроля версий с помощью GOVCS
Возможность команды go скачивать модули с помощью команд системы контроля версий, таких как git, критична для децентрализованной экосистемы пакетов, в которой код может быть импортирован с любого сервера. Это также потенциальная проблема безопасности, если злонамеренный сервер найдёт способ заставить вызываемую команду системы контроля версий выполнить непреднамеренный код.
Чтобы сбалансировать функциональность и обеспечение безопасности, команда go по умолчанию будет использовать только git и hg для загрузки кода с публичных серверов. Она будет использовать любой известный систему контроля версий для загрузки кода с частных серверов, определённых как серверы, хостящие пакеты, соответствующие переменной среды GOPRIVATE переменная среды. Основанием для разрешения использования только Git и Mercurial является то, что эти две системы получили наибольшее внимание в вопросах безопасности при работе в качестве клиентов ненадёжных серверов. В отличие от этого, Bazaar, Fossil и Subversion в основном использовались в доверенных, аутентифицированных средах и не так хорошо проверены с точки зрения возможных атак.
Ограничения команды управления версиями применяются только при прямом доступе к системе контроля версий для загрузки кода. При загрузке модулей через прокси, команда go использует GOPROXY протокол, который всегда разрешён. По умолчанию команда go использует зеркало Go модулей (proxy.golang.org) для публичных модулей и возвращается к системе контроля версий только для приватных модулей или когда зеркало отказывается обслуживать публичный пакет (обычно по юридическим причинам). Таким образом, клиенты по-прежнему могут получать доступ к публичному коду, размещённому в репозиториях Bazaar, Fossil или Subversion по умолчанию, поскольку такие загрузки используют зеркало Go модулей, которое берёт на себя риск выполнения команд системы контроля версий с использованием пользовательской песочницы.
Переменная GOVCS может использоваться для изменения разрешённых систем управления версиями для конкретных модулей. Переменная GOVCS применяется при сборке пакетов как в режиме модулей, так и в режиме GOPATH. При использовании модулей, шаблоны соответствуют пути модуля. При использовании GOPATH, шаблоны соответствуют пути импорта, соответствующему корню репозитория системы контроля версий.
Общий формат переменной GOVCS представляет собой список правил pattern:vcslist, разделённых запятыми. Шаблон — это glob-шаблон, который должен соответствовать одному или нескольким начальным элементам пути модуля или импорта. vcslist — это список разрешённых команд системы контроля версий, разделённых вертикальной чертой, или all для разрешения использования любой известной команды, или off для запрета использования любых команд. Обратите внимание, что если модуль соответствует шаблону с vcslist off, он может всё ещё быть загружен, если исходный сервер использует схему mod, которая указывает команде go загрузить модуль с использованием GOPROXY протокола. Первое совпадающее правило в списке применяется, даже если позже идущие шаблоны также могут совпадать.
Например, рассмотрим:
<code>GOVCS=github.com:git,evil.com:off,*:git|hg </code>
С таким параметром код с путём модуля или импорта, начинающимся с github.com/, может использовать только git; пути на evil.com не могут использовать никакие команды системы контроля версий, а все остальные пути (* соответствует всему) могут использовать только git или hg.
Специальные шаблоны public и private соответствуют публичным и приватным путям модулей или импорта. Путь считается приватным, если он соответствует переменной GOPRIVATE; в противном случае он считается публичным.
Если ни одно из правил переменной GOVCS не соответствует конкретному модулю или пути импорта, команда go применяет своё правило по умолчанию, которое теперь можно описать в нотации GOVCS как public:git|hg,private:all.
Для разрешения неограниченного использования любой системы управления версиями для любого пакета используйте:
<code>GOVCS=*:all </code>
Чтобы отключить использование системы управления версиями, используйте:
<code>GOVCS=*:off </code>
Команда go env -w может быть использована для установки переменной GOVCS для будущих вызовов команды go.
Переменная GOVCS была введена в Go 1.16. Более ранние версии Go могут использовать любые известные инструменты системы управления версиями для любого модуля.
Файлы модулей в формате zip
Версии модулей распространяются в виде файлов .zip. Обычно нет необходимости напрямую взаимодействовать с этими файлами, поскольку команда go автоматически создает, скачивает и извлекает их из прокси модулей и репозиториев системы управления версиями. Однако полезно знать о таких файлах, чтобы понимать ограничения совместимости между платформами или при реализации прокси модулей.
Команда go mod download скачивает zip-файлы для одного или нескольких модулей, а затем извлекает эти файлы в кэш модулей. В зависимости от GOPROXY и других переменных окружения, команда go может либо скачивать zip-файлы с прокси, либо клонировать репозитории системы управления версиями и создавать zip-файлы из них. Флаг -json может быть использован для определения местоположения скачанных zip-файлов и их распакованных содержимых в кэше модулей.
Пакет golang.org/x/mod/zip может быть использован для программного создания, извлечения или проверки содержимого zip-файлов.
Ограничения на размер и путь файлов
Существует ряд ограничений на содержимое zip-файлов модулей. Эти ограничения обеспечивают безопасное и согласованное извлечение zip-файлов на широком диапазоне платформ.
- Размер zip-файла модуля не должен превышать 500 МиБ. Общий размер распакованных файлов также ограничен 500 МиБ. Файлы
go.modограничены 16 МиБ. ФайлыLICENSEтакже ограничены 16 МиБ. Эти ограничения существуют для защиты от атак типа "отказ в обслуживании" для пользователей, прокси и других частей экосистемы модулей. Репозитории, содержащие более 500 МиБ файлов в дереве каталогов модуля, должны тегировать версии модулей на коммитах, которые включают только файлы, необходимые для сборки пакетов модуля; видео, модели и другие большие ресурсы обычно не требуются для сборки. - Каждый файл внутри zip-файла модуля должен начинаться с префикса
$module@$version/, где$module— это путь модуля, а$version— версия, например,golang.org/x/mod@v0.3.0/. Путь модуля должен быть корректным, версия — корректной и канонической, а также версия должна соответствовать суффиксу основной версии пути модуля. См. Пути и версии модулей для конкретных определений и ограничений. - Режимы файлов, временные метки и другая метаинформация игнорируются.
- Пустые каталоги (записи с путями, заканчивающимися на слэш) могут быть включены в zip-файлы модулей, но не извлекаются. Команда
goне включает пустые каталоги в создаваемые ею zip-файлы. - Символические ссылки и другие неправильные файлы игнорируются при создании zip-файлов, поскольку они не переносимы между операционными системами и файловыми системами, и нет переносимого способа их представления в формате zip.
- Файлы внутри каталогов с именем
vendorигнорируются при создании zip-файлов, поскольку каталогиvendorвне основного модуля никогда не используются. - Файлы внутри каталогов, содержащих файлы
go.mod, кроме корневого каталога модуля, игнорируются при создании zip-файлов, поскольку они не являются частью модуля. Командаgoигнорирует подкаталоги, содержащие файлыgo.mod, при извлечении zip-файлов. - Ни два файла внутри zip-файла не могут иметь одинаковые пути при Unicode case-folding (см.
strings.EqualFold). Это гарантирует, что zip-файлы могут быть извлечены на файловых системах с нечувствительным к регистру именованием без конфликтов. - Файл
go.modможет находиться либо в корневом каталоге ($module@$version/go.mod), либо нет. Если он присутствует, он должен иметь имяgo.mod(все строчные буквы). Файлы с именемgo.modне допускаются ни в каких других каталогах. - Имена файлов и каталогов внутри модуля могут состоять из букв Unicode, десятичных цифр ASCII, пробельного символа ASCII (U+0020) и знаков препинания ASCII
!#$%&()+,-.=@[]^_{}~. Обратите внимание, что пути пакетов не могут содержать все эти символы. См.module.CheckFilePathиmodule.CheckImportPathдля различий. - Имя файла или каталога до первого символа точки не должно быть зарезервированным именем файла в Windows, независимо от регистра (
CON,com1,NuLи т. д.).
Приватные модули
Go модули часто разрабатываются и распространяются на серверах системы управления версиями и прокси-серверах, которые недоступны в публичном интернете. Команда go может скачивать и собирать модули из приватных источников, хотя обычно требуется некоторая настройка.
Переменные окружения, указанные ниже, могут использоваться для настройки доступа к приватным модулям. Подробности см. в разделе Переменные окружения. Также обратите внимание на раздел Конфиденциальность для информации о контроле передаваемой информации на публичные серверы.
GOPROXY— список URL-адресов прокси-серверов модулей. Командаgoпопытается загрузить модули с каждого сервера по очереди. Ключевое словоdirectуказывает командеgoзагружать модули из репозиториев системы управления версиями, где они разрабатываются, вместо использования прокси.GOPRIVATE— список шаблонов глобальных масок префиксов путей модулей, которые должны считаться приватными. Выступает в качестве значения по умолчанию дляGONOPROXYиGONOSUMDB.GONOPROXY— список шаблонов глобальных масок префиксов путей модулей, которые не должны скачиваться через прокси. Командаgoбудет скачивать соответствующие модули из репозиториев системы управления версиями, где они разрабатываются, независимо от значенияGOPROXY.GONOSUMDB— список шаблонов глобальных масок префиксов путей модулей, которые не должны проверяться с использованием публичной базы контрольных сумм, sum.golang.org.GOINSECURE— список шаблонов глобальных масок префиксов путей модулей, которые могут быть получены по протоколам HTTP и другим небезопасным протоколам.
Эти переменные могут быть установлены в среде разработки (например, в файле .profile), или же могут быть установлены навсегда с помощью команды go env -w.
Остальная часть этого раздела описывает распространённые сценарии предоставления доступа к приватным прокси-серверам модулей и репозиториям системы управления версиями.
Приватный прокси, обслуживающий все модули
Централизованный приватный прокси-сервер, который обслуживает все модули (публичные и приватные), обеспечивает наибольший контроль для администраторов и требует минимальной настройки отдельных разработчиков.
Чтобы настроить команду go на использование такого сервера, установите следующие переменные окружения, заменив https://proxy.corp.example.com на URL вашего прокси и corp.example.com на префикс вашего модуля:
<code>GOPROXY=https://proxy.corp.example.com GONOSUMDB=corp.example.com </code>
Настройка GOPROXY указывает команде go скачивать модули только с https://proxy.corp.example.com; команда go не будет подключаться к другим прокси или репозиториям системы управления версиями.
Настройка GONOSUMDB указывает команде go не использовать публичную базу контрольных сумм для аутентификации модулей с путями, начинающимися с corp.example.com.
Прокси, работающий в таком режиме, вероятно, потребует доступ на чтение к частным серверам контроля версий. Также ему понадобится доступ к публичному интернету для загрузки новых версий публичных модулей.
Существует несколько реализаций серверов GOPROXY, которые могут использоваться именно таким образом. Минимальная реализация будет обслуживать файлы из каталога кэша модулей и будет использовать go mod download (с соответствующей настройкой) для получения отсутствующих модулей.
Частный прокси, обслуживающий частные модули
Частный прокси-сервер может обслуживать частные модули, не предоставляя доступ к общедоступным модулям. Команда go может быть настроена так, чтобы возвращаться к публичным источникам для модулей, недоступных на частном сервере.
Чтобы настроить команду go таким образом, установите следующие переменные окружения, заменив https://proxy.corp.example.com URL прокси и corp.example.com префикс модуля:
<code>GOPROXY=https://proxy.corp.example.com,https://proxy.golang.org,direct GONOSUMDB=corp.example.com </code>
Настройка GOPROXY указывает команде go сначала пытаться загрузить модули с https://proxy.corp.example.com. Если этот сервер отвечает кодом 404 (Not Found) или 410 (Gone), команда go переключится на https://proxy.golang.org, а затем на прямое подключение к репозиториям.
Настройка GONOSUMDB указывает команде go не использовать публичную базу контрольных сумм для аутентификации модулей, чьи пути начинаются с corp.example.com.
Обратите внимание, что прокси, используемый в этой конфигурации, может по-прежнему контролировать доступ к публичным модулям, даже если он их не предоставляет. Если прокси отвечает на запрос с кодом ошибки, отличным от 404 или 410, команда go не будет переходить к следующим записям в списке GOPROXY. Например, прокси может отвечать кодом 403 (Forbidden) для модуля с неподходящей лицензией или с известными уязвимостями безопасности.
Прямой доступ к частным модулям
Команда go может быть настроена так, чтобы обходить публичные прокси и напрямую загружать частные модули с серверов контроля версий. Это полезно, когда запуск частного прокси-сервера невозможен или нецелесообразен.
Чтобы настроить команду go таким образом, установите GOPRIVATE, заменив corp.example.com префикс частного модуля:
<code>GOPRIVATE=corp.example.com </code>
В этом случае переменная GOPROXY изменять не требуется. По умолчанию она равна https://proxy.golang.org,direct, что указывает команде go сначала пытаться загрузить модули с https://proxy.golang.org, а затем, если этот прокси отвечает кодом 404 (Not Found) или 410 (Gone), использовать прямое подключение к репозиториям.
Настройка GOPRIVATE указывает команде go не подключаться к прокси или к базе данных контрольных сумм для модулей, начинающихся с corp.example.com.
Внутренний HTTP-сервер может всё ещё потребоваться для разрешения путей модулей в URL-адреса репозиториев. Например, когда команда go загружает модуль corp.example.com/mod, она отправит GET-запрос на https://corp.example.com/mod?go-get=1 и будет искать URL репозитория в ответе. Чтобы избежать этого требования, убедитесь, что каждый путь приватного модуля имеет суффикс VCS (например, .git), обозначающий префикс корня репозитория. Например, когда команда go загружает модуль corp.example.com/repo.git/mod, она клонирует Git-репозиторий по адресу https://corp.example.com/repo.git или ssh://corp.example.com/repo.git, не требуя дополнительных запросов.
Разработчикам потребуется право на чтение репозиториев, содержащих приватные модули. Это может быть настроено в глобальных конфигурационных файлах VCS, таких как .gitconfig. Лучше всего настроить инструменты VCS так, чтобы они не требовали интерактивных запросов аутентификации. По умолчанию, при вызове Git команда go отключает интерактивные запросы, устанавливая GIT_TERMINAL_PROMPT=0, но она уважает явные настройки.
Передача учётных данных приватным прокси
Команда go поддерживает HTTP базовую аутентификацию при взаимодействии с серверами прокси.
Учётные данные могут быть указаны в файле .netrc. Например, файл .netrc, содержащий строки ниже, настроит команду go на подключение к машине proxy.corp.example.com с указанным именем пользователя и паролем.
<code>machine proxy.corp.example.com login jrgopher password hunter2 </code>
Расположение файла может быть задано переменной окружения NETRC. Если NETRC не задана, команда go будет читать $HOME/.netrc на UNIX-подобных платформах или %USERPROFILE%\_netrc на Windows.
Поля в .netrc разделяются пробелами, табуляцией и символами новой строки. К сожалению, эти символы нельзя использовать в именах пользователей или паролях. Также обратите внимание, что имя машины не может быть полным URL, поэтому невозможно указать разные имена пользователей и пароли для разных путей на одной и той же машине.
Альтернативно, учётные данные могут быть указаны непосредственно в URL-адресах GOPROXY. Например:
<code>GOPROXY=https://jrgopher:hunter2@proxy.corp.example.com </code>
Используйте осторожность при использовании этого подхода: переменные окружения могут отображаться в истории оболочки и логах.
Передача учётных данных в частные репозитории
Команда go может загружать модуль непосредственно из репозитория системы управления версиями.
Это необходимо для частных модулей, если не используется частный прокси-сервер.
См. Прямой доступ к частным модулям для настройки.
Команда go запускает инструменты системы управления версиями, такие как git, при загрузке модулей напрямую.
Эти инструменты выполняют свою собственную аутентификацию, поэтому может потребоваться настроить учётные данные в файле конфигурации инструмента, например .gitconfig.
Чтобы всё работало корректно, убедитесь, что команда go использует правильный URL репозитория и что инструмент управления версиями не требует ввода пароля в интерактивном режиме.
Команда go предпочитает URL-адреса с https:// перед другими схемами, такими как ssh://, если схема не была указана при поиске URL репозитория.
В частности, для репозиториев GitHub команда go предполагает использование https://.
Для большинства серверов можно настроить клиент для аутентификации через HTTP.
Например, GitHub поддерживает использование токенов личного доступа OAuth в качестве HTTP-паролей.
Можно хранить HTTP-пароли в файле .netrc, как это делается при передаче учётных данных в частные прокси-серверы.
Альтернативно, можно изменить URL-адреса https:// на другую схему.
Например, в .gitconfig:
<code>[url "git@github.com:"] insteadOf = https://github.com/ </code>
Для получения дополнительной информации см. Почему команда “go get” использует HTTPS при клонировании репозитория?
Конфиденциальность
Команда go может загружать модули и метаданные с серверов прокси-серверов модулей и систем управления версиями.
Переменная окружения GOPROXY определяет, какие серверы будут использоваться.
Переменные окружения GOPRIVATE и GONOPROXY контролируют, какие модули будут извлекаться из прокси-серверов.
Значение по умолчанию для GOPROXY:
<c></c>