Кроссплатформенные подключаемые модули NuGet

В NuGet 4.8+ добавлена поддержка кроссплатформенных подключаемых модулей. Это достигается путем создания новой модели расширяемости подключаемых модулей, которая должна соответствовать строгому набору правил работы. Подключаемые модули представляют собой самодостаточные исполняемые файлы (в терминах .NET Core — запускаемые), которые клиенты NuGet запускают в отдельном процессе. Это истинная реализация подхода "пишешь один раз — запускаешь везде". Он будет работать со всеми клиентскими средствами NuGet. Подключаемые модули могут быть либо .NET Framework (NuGet.exe, MSBuild.exe и Visual Studio), либо .NET Core (dotnet.exe). Определена версия протокола связи между клиентом NuGet и подключаемым модулем. Во время подтверждения при запуске 2 процесса согласовывают версию протокола.

Чтобы охватить все сценарии клиентских средств NuGet, требуется как .NET Framework, так и подключаемый модуль .NET Core. Ниже описаны сочетания клиента и платформы для подключаемых модулей.

Средство клиента Платформа
Visual Studio .NET Framework
dotnet.exe .NET Core
NuGet.exe .NET Framework
MSBuild.exe .NET Framework
NuGet. exe на Mono .NET Framework

Как это работает

На высоком уровне рабочий процесс можно описать следующим образом.

  1. NuGet обнаруживает доступные подключаемые модули.
  2. Когда применимо, NuGet перебирает подключаемые модули в порядке приоритета и запускает их по одному.
  3. NuGet будет использовать первый подключаемый модуль, который может обслужить запрос.
  4. Когда подключаемые модули больше не нужны, их работа завершается.

Общие требования к подключаемому модулю

Текущая версия протокола — 2.0.0. Ниже приведены требования к этой версии.

  • Наличие действительной доверенной сборки с Authenticode-подписью, которая будут выполняться в Windows и Mono. Никаких специальных требований к доверию для сборок, работающих в Linux и Mac, пока нет. Соответствующая проблема
  • Поддержка запуска без отслеживания состояния в текущем контексте безопасности клиентских средств NuGet. Например, клиентские средства NuGet не будут выполнять повышение или дополнительную инициализацию за пределами протокола подключаемого модуля, описанного ниже.
  • Быть неинтерактивным, если явно не указано иное.
  • Придерживаться согласованной версии протокола подключаемого модуля.
  • Отвечать на все запросы в течение разумного периода времени.
  • Выполнять запросы на отмену для любой выполняющейся операции.

Техническая спецификация подробно описана в следующих документах.

Взаимодействие клиента и подключаемого модуля

Клиентские средства NuGet и подключаемые модули взаимодействуют с помощью JSON через стандартные потоки (stdin, stdout, stderr). Все данные должны иметь кодировку UTF-8. Подключаемые модули запускаются с аргументом "-Plugin". Если пользователь непосредственно запускает исполняемый файл подключаемого модуля без этого аргумента, подключаемый модуль может предоставить информативное сообщение вместо того, чтобы ждать подтверждения протокола. Время ожидания подтверждения протокола — 5 секунд. Плагин должен завершить настройку в максимально короткое время. Клиентские средства NuGet запрашивают поддерживаемые операции подключаемого модуля, передавая индекс службы для источника NuGet. Подключаемый модуль может использовать индекс службы для проверки наличия поддерживаемых типов служб.

Обмен данными между клиентскими инструментами NuGet и подключаемым модулем осуществляется по двунаправленному соединению. Время ожидания каждого запроса составляет 5 секунд. Если операции должны занять больше времени, соответствующий процесс должен отправить сообщение о ходе выполнения, чтобы предотвратить время ожидания запроса. Через 1 минуту бездействия подключаемый модуль считается неактивным и завершает работу.

Установка и обнаружение подключаемого модуля

Подключаемые модули можно будет обнаружить с помощью структуры каталогов на основе соглашений. Сценарии CI/CD и опытные пользователи могут использовать переменные среды для переопределения поведения. При использовании переменных среды разрешены только абсолютные пути. Обратите внимание, что NUGET_NETFX_PLUGIN_PATHS и NUGET_NETCORE_PLUGIN_PATHS доступны только в средстве NuGet версии 5.3+ и более поздних.

  • NUGET_NETFX_PLUGIN_PATHS — определяет подключаемые модули, которые будут использоваться инструментами на основе .NET Framework (NuGet.exe/MSBuild.exe/Visual Studio). Имеет больший приоритет, чем NUGET_PLUGIN_PATHS. (Только для NuGet версии 5.3+)
  • NUGET_NETCORE_PLUGIN_PATHS — определяет подключаемые модули, которые будут использоваться инструментами на основе .NET Core (dotnet.exe). Имеет больший приоритет, чем NUGET_PLUGIN_PATHS. (Только для NuGet версии 5.3+)
  • NUGET_PLUGIN_PATHS — определяет подключаемые модули, которые будут использоваться для этого процесса NuGet, приоритет сохраняется. Если эта переменная среды задана, она переопределяет обнаружение на основе соглашения. Игнорируется, если указана любая из переменных для определенной платформы.
  • Расположение пользователя, корневое расположение NuGet в %UserProfile%/.nuget/plugins. Это расположение нельзя переопределить. Для подключаемых модулей .NET Core и .NET Framework будет использоваться другой корневой каталог.
Платформа Корневое расположение для обнаружения
.NET Core %UserProfile%/.nuget/plugins/netcore
.NET Framework %UserProfile%/.nuget/plugins/netfx

Каждый подключаемый модуль должен быть установлен в отдельную папку. Точкой входа подключаемого модуля будет имя установленной папки с расширениями DLL для .NET Core и расширением EXE для .NET Framework.

.nuget
    plugins
        netfx
            myPlugin
                myPlugin.exe
                nuget.protocol.dll
                ...
        netcore
            myPlugin
                myPlugin.dll
                nuget.protocol.dll
                ...

Примечание.

В настоящее время нет пользовательской истории для установки подключаемых модулей. Это так же просто, как перемещение необходимых файлов в предварительно определенное расположение.

Поддерживаемые операции

В новом протоколе подключаемых модулей поддерживаются две операции.

Наименование операции Минимальная версия протокола Минимальная версия клиента NuGet
Загрузка пакета 1.0.0 4.3.0
Аутентификация 2.0.0 4.8.0

Запуск подключаемых модулей в правильной среде выполнения

Для NuGet в сценариях dotnet.exe подключаемые модули должны иметь возможность выполнения в этой конкретной среде выполнения файла dotnet.exe. Поставщик подключаемого модуля и потребитель должны убедиться, что используется совместимая комбинация dotnet.exe и подключаемого модуля. При использовании подключаемых модулей пользовательского расположения может возникнуть потенциальная ошибка. Например, dotnet.exe в среде выполнения 2.0 попытается использовать подключаемый модуль, написанный для среды выполнения 2.1.

Возможности кэширования

Проверка безопасности и создание экземпляров подключаемых модулей являются затратными операциями. Операция загрузки выполняется чаще, чем операция проверки подлинности, однако обычный пользователь NuGet, скорее всего, будет иметь подключаемый модуль проверки подлинности. Чтобы улучшить работу, NuGet кэширует утверждения операций для данного запроса. Этот кэш предназначен для каждого подключаемого модуля с ключом подключаемого модуля, который является путем к нему, а срок действия этого кэша возможностей составляет 30 дней.

Кэш находится в папке %LocalAppData%/NuGet/plugins-cache, которую можно переопределить с помощью переменной среды NUGET_PLUGINS_CACHE_PATH. Чтобы очистить кэш, можно выполнить команду locals с параметром plugins-cache. Параметр all команды locals теперь также будет удалять кэш подключаемых модулей.

Перечень сообщений протокола

Сообщения протокола версии 1.0.0.

  1. Закрытие

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос не содержит полезных данных
    • Ответ не ожидается. Правильный ответ заключается в том, что процесс подключаемого модуля будет быстро завершен.
  2. Копировать файлы пакета

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • идентификатор и версия пакета
      • расположение исходного репозитория пакета
      • путь к каталогу назначения
      • перечисление файлов пакета для копирования в каталог назначения
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
      • перечисление полных путей для скопированных файлов в целевом каталоге, если операция выполнена успешно
  3. Копировать файл пакета (.nupkg)

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • идентификатор и версия пакета
      • расположение исходного репозитория пакета
      • путь к файлу назначения
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
  4. Получение учетных данных

    • Направление запроса: подключаемый модуль —> NuGet
    • Запрос будет содержать следующее:
      • расположение исходного репозитория пакета
      • код состояния HTTP, полученный из исходного репозитория пакета с использованием текущих учетных данных
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
      • имя пользователя, если оно доступно
      • пароль, если он доступен
  5. Получить файлы пакета

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • идентификатор и версия пакета
      • расположение исходного репозитория пакета
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
      • перечисление путей файлов в пакете, если операция выполнена успешно
  6. Получение утверждений операции

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • индекс службы в формате JSON для источника пакета
      • расположение исходного репозитория пакета
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
      • перечисление поддерживаемых операций (например, скачивание пакета), если операция выполнена успешно. Если подключаемый модуль не поддерживает источник пакета, подключаемый модуль должен вернуть пустой набор поддерживаемых операций.

Примечание.

Это сообщение было изменено в версии 2.0.0. Оно находится на клиенте для сохранения обратной совместимости.

  1. Получение хэша пакета

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • идентификатор и версия пакета
      • расположение исходного репозитория пакета
      • хэш-алгоритм
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
      • хэш файла пакета с использованием запрошенного хэш-алгоритма, если операция выполнена успешно
  2. Получение версий пакета

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • идентификатор пакета
      • расположение исходного репозитория пакета
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
      • перечисление версий пакета, если операция выполнена успешно
  3. Получение индекса службы

    • Направление запроса: подключаемый модуль —> NuGet
    • Запрос будет содержать следующее:
      • расположение исходного репозитория пакета
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
      • индекс службы, если операция выполнена успешно
  4. Рукопожатие

    • Направление запроса: NuGet <—> подключаемый модуль
    • Запрос будет содержать следующее:
      • текущая версия протокола подключаемых модулей
      • минимальная поддерживаемая версия протокола подключаемых модулей
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
      • согласованная версия протокола, если операция выполнена успешно. В случае сбоя произойдет завершение работы подключаемого модуля.
  5. Инициализация

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • версия клиентского средства NuGet
      • действующий язык клиентского средства NuGet. При этом учитывается параметр ForceEnglishOutput, если он используется.
      • время ожидания запроса по умолчанию, заменяющее значение протокола по умолчанию.
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции. В случае сбоя произойдет завершение работы подключаемого модуля.
  6. Журнал

    • Направление запроса: подключаемый модуль —> NuGet
    • Запрос будет содержать следующее:
      • уровень ведения журнала для запроса
      • сообщение для записи в журнал
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции.
  7. Мониторинг завершения процесса NuGet

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • идентификатор процесса NuGet
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции.
  8. Предварительная загрузка пакета

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • идентификатор и версия пакета
      • расположение исходного репозитория пакета
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
  9. Настройка учетных данных

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • расположение исходного репозитория пакета
      • последнее известное имя пользователя источника пакета, если оно доступно
      • последний известный пароль источника пакета, если он доступен
      • последнее известное имя пользователя прокси-сервера, если оно доступно
      • последний известный пароль прокси-сервера, если он доступен
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
  10. Установка уровня ведения журнала

    • Направление запроса: NuGet —> подключаемый модуль
    • Запрос будет содержать следующее:
      • уровень ведения журнала по умолчанию
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции

Сообщения протокола версии 2.0.0.

  1. Получение утверждений операции
  • Направление запроса: NuGet —> подключаемый модуль

    • Запрос будет содержать следующее:
      • индекс службы в формате JSON для источника пакета
      • расположение исходного репозитория пакета
    • Ответ будет содержать следующее:
      • код ответа, указывающий результат операции
      • перечисление поддерживаемых операций, если операция выполнена успешно. Если подключаемый модуль не поддерживает источник пакета, подключаемый модуль должен вернуть пустой набор поддерживаемых операций.

    Если индекс службы и источник пакета имеют значение NULL, то подключаемый модуль может ответить проверкой подлинности.

  1. Получение учетных данных проверки подлинности
  • Направление запроса: NuGet —> подключаемый модуль
  • Запрос будет содержать следующее:
    • URI-адрес
    • isRetry
    • NonInteractive
    • CanShowDialog
  • Ответ будет содержать
    • Username
    • Пароль
    • Сообщение
    • Список типов проверки подлинности
    • MessageResponseCode