Plug-ins multiplateformes NuGet

La prise en charge des plug-ins multiplateformes a été ajoutée dans NuGet 4.8+. Cela a été réalisé par le biais de la création d’un nouveau modèle d’extensibilité de plug-in, qui doit se conformer à un ensemble strict de règles d’opération. Les plug-ins sont des exécutables autonomes (exécutables dans le monde .NET Core), que les clients NuGet lancent dans un processus distinct. Il s’agit d’un véritable plug-in « write once, run everywhere » (écrire une fois, exécuter partout.) Il fonctionne avec tous les outils clients NuGet. Les plug-ins peuvent être .NET Framework (NuGet.exe, MSBuild.exe et Visual Studio) ou .NET Core (dotnet.exe). Un protocole de communication avec version entre le client NuGet et le plug-in est défini. Pendant la négociation de démarrage, les 2 processus négocient la version du protocole.

Pour couvrir tous les scénarios d’outils clients NuGet, il faudrait à la fois un plug-in .NET Core et .NET Framework. La section ci-dessous décrit les combinaisons client/infrastructure des plug-ins.

Outil client Infrastructure
Visual Studio .NET Framework
dotnet.exe .NET Core
NuGet.exe .NET Framework
MSBuild.exe .NET Framework
NuGet.exe sur Mono .NET Framework

Fonctionnement

Le flux de travail de haut niveau peut être décrit comme suit :

  1. NuGet découvre les plug-ins disponibles.
  2. Le cas échéant, NuGet effectue une itération sur les plug-ins dans l’ordre de priorité et les démarre un par un.
  3. NuGet utilise le premier plug-in qui peut traiter la requête.
  4. Les plug-ins seront arrêtés lorsqu’ils ne sont plus nécessaires.

Exigences générales du plug-in

La version actuelle du protocole est 2.0.0. Dans cette version, les exigences sont les suivantes :

  • Disposer d’assemblys de signature Authenticode valides et approuvés qui s’exécuteront sur Windows et Mono. Il n’existe pas encore de conditions d’approbation particulières pour les assemblys exécutés sur Linux et Mac. Problème pertinent
  • Prendre en charge le lancement sans état dans le contexte de sécurité actuel des outils clients NuGet. Par exemple, les outils clients NuGet n’effectuent pas d’élévation ou d’initialisation supplémentaire en dehors du protocole de plug-in décrit ultérieurement.
  • Ne pas être interactif, sauf indication explicite.
  • Respecter la version négociée du protocole de plug-in.
  • Répondre à toutes les requêtes dans un délai raisonnable.
  • Honorer les requêtes d’annulation pour toute opération en cours.

La spécification technique est décrite plus en détail dans les caractéristiques suivantes :

Interaction entre le client et le plug-in

Les outils clients NuGet et les plug-ins communiquent avec JSON sur des flux standard (stdin, stdout, stderr). Toutes les données doivent être encodées en UTF-8. Les plug-ins sont lancés avec l’argument « -Plugin ». Si un utilisateur lance directement un exécutable de plug-in sans cet argument, le plug-in peut donner un message d’information au lieu d’attendre une négociation de protocole. Le délai d’expiration pour l’établissement d’une liaison de protocole est de 5 secondes. Le plug-in doit terminer le programme d’installation dans un délai aussi court que possible. Les outils clients NuGet interrogent les opérations prises en charge par un plug-in en transmettant l’index de service pour une source NuGet. Un plug-in peut utiliser l’index de service pour vérifier la présence des types de service pris en charge.

La communication entre les outils clients NuGet et le plug-in est bidirectionnelle. Chaque requête a un délai d’expiration de 5 secondes. Si les opérations sont censées prendre plus de temps, le processus respectif doit envoyer un message de progression pour empêcher la demande d’expirer. Après 1 minute d’inactivité, le plug-in est considéré comme inactif et est arrêté.

Découverte et installation du plug-in

Les plug-ins seront découverts via une structure de répertoires basée sur une convention. Les scénarios CI/CD et les utilisateurs avec pouvoir peuvent utiliser des variables d’environnement pour remplacer le comportement. Lorsque vous utilisez des variables d’environnement, seuls les chemins d’accès absolus sont autorisés. Notez que NUGET_NETFX_PLUGIN_PATHS et NUGET_NETCORE_PLUGIN_PATHS sont disponibles uniquement avec la version 5.3+ des outils NuGet et les versions ultérieures.

  • NUGET_NETFX_PLUGIN_PATHS – définit les plug-ins qui seront utilisés par les outils basés sur .NET Framework (NuGet.exe/MSBuild.exe/Visual Studio). Est prioritaire par rapport à NUGET_PLUGIN_PATHS. (NuGet version 5.3+ uniquement)
  • NUGET_NETCORE_PLUGIN_PATHS – définit les plug-ins qui seront utilisés par les outils basés sur .NET Core (dotnet.exe). Est prioritaire par rapport à NUGET_PLUGIN_PATHS. (NuGet version 5.3+ uniquement)
  • NUGET_PLUGIN_PATHS – définit les plug-ins qui seront utilisés pour ce processus NuGet, priorité conservée. Si cette variable d’environnement est définie, elle remplace la découverte basée sur la convention. Ignoré si l’une des variables spécifiques à l’infrastructure est spécifiée.
  • Emplacement utilisateur, emplacement d’accueil NuGet dans %UserProfile%/.nuget/plugins. Cet emplacement ne peut pas être remplacé. Un autre répertoire racine sera utilisé pour les plug-ins .NET Core et .NET Framework.
Infrastructure Emplacement de découverte racine
.NET Core %UserProfile%/.nuget/plugins/netcore
.NET Framework %UserProfile%/.nuget/plugins/netfx

Chaque plug-in doit être installé dans son propre dossier. Le point d’entrée du plug-in sera le nom du dossier installé, avec les extensions .dll pour .NET Core et l’extension .exe pour .NET Framework.

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

Remarque

Il n’existe actuellement aucun récit utilisateur pour l’installation des plug-ins. Il est aussi simple que de déplacer les fichiers requis vers l’emplacement prédéterminé.

Opérations prises en charge

Deux opérations sont prises en charge sous le nouveau protocole de plug-in.

Nom de l’opération Version minimale du protocole Version minimale du client NuGet
Télécharger le package 1.0.0 4.3.0
Authentification 2.0.0 4.8.0

Exécution de plug-ins dans le runtime correct

Pour les scénarios NuGet dans dotnet.exe, les plug-ins doivent pouvoir s’exécuter dans ce runtime spécifique de dotnet.exe. Il se trouve sur le fournisseur de plug-in et le consommateur pour garantir qu’une combinaison dotnet.exe/plug-in compatible est utilisée. Un problème potentiel peut survenir avec les plug-ins d’emplacement utilisateur lorsque, par exemple, un dotnet.exe dans le runtime 2.0 tente d’utiliser un plug-in écrit pour le runtime 2.1.

Mise en cache des fonctionnalités

La vérification de la sécurité et l’instanciation des plug-ins sont coûteuses. L’opération de téléchargement se produit plus fréquemment que l’opération d’authentification, mais l’utilisateur NuGet moyen est susceptible d’avoir un plug-in d’authentification. Pour améliorer l’expérience, NuGet met en cache les revendications d’opération pour la requête donnée. Ce cache est par plug-in, la clé de plug-in étant le chemin d’accès du plug-in. L’expiration de ce cache de fonctionnalités est de 30 jours.

Le cache se trouve dans %LocalAppData%/NuGet/plugins-cache et doit être remplacé par la variable d’environnement NUGET_PLUGINS_CACHE_PATH. Pour effacer ce cache, vous pouvez exécuter la commande locale avec l’option plugins-cache. L’option de variables locales all supprime désormais également le cache des plug-ins.

Index des messages de protocole

Messages de la version 1.0.0 du protocole :

  1. Clôture

    • Direction de la requête : NuGet – plug-in >
    • La requête ne contiendra aucune charge utile
    • Aucune réponse n’est attendue. La réponse appropriée est que le processus de plug-in se ferme rapidement.
  2. Copier des fichiers dans le package

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • la version et l’identifiant du package
      • l’emplacement du référentiel source du package
      • le chemin d’accès du répertoire de destination
      • un énumérable de fichiers dans le package à copier dans le chemin d’accès du répertoire de destination
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
      • un énumérable de chemins complets pour les fichiers copiés dans le l’annuaire de destination si l’opération a réussi
  3. Copier le fichier de package (.nupkg)

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • la version et l’identifiant du package
      • l’emplacement du référentiel source du package
      • le chemin d’accès du fichier de destination
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
  4. Récupérer les informations d’identification

    • Direction de la requête : plug-in – NuGet >
    • La requête contient les éléments suivants :
      • l’emplacement du référentiel source du package
      • le code d’état HTTP obtenu à partir du référentiel source du package à l’aide des identifiants actuels
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
      • un nom d’utilisateur, le cas échéant
      • un mot de passe, le cas échéant
  5. Récupérer les fichiers du package

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • la version et l’identifiant du package
      • l’emplacement du référentiel source du package
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
      • un énumérable des chemins d’accès de fichier dans le package si l’opération a réussi
  6. Obtenir les revendications d’opération

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • le service index.json pour une source de package
      • l’emplacement du référentiel source du package
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
      • un énumérable des opérations prises en charge (par exemple, téléchargement de package) si l’opération a réussi. Si un plug-in ne prend pas en charge la source du package, le plug-in doit retourner un ensemble vide d’opérations prises en charge.

Remarque

Ce message a été mis à jour dans la version 2.0.0. Il incombe au client de préserver la compatibilité descendante.

  1. Obtenir le hachage du package

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • la version et l’identifiant du package
      • l’emplacement du référentiel source du package
      • l’algorithme de hachage
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
      • un hachage de fichier de package à l’aide de l’algorithme de hachage demandé si l’opération a réussi
  2. Obtenir des versions de packages

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • l’identifiant du package
      • l’emplacement du référentiel source du package
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
      • un énumérable des versions de package si l’opération a réussi
  3. Obtenir l’index de service

    • Direction de la requête : plug-in – NuGet >
    • La requête contient les éléments suivants :
      • l’emplacement du référentiel source du package
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
      • l’index de service si l’opération a réussi
  4. Poignée de main

    • Direction de la requête : NuGet <–> plug-in
    • La requête contient les éléments suivants :
      • la version actuelle du protocole de plug-in
      • la version minimale prise en charge du protocole de plug-in
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
      • la version de protocole négociée si l’opération a réussi. Une défaillance entraîne l’arrêt du plug-in.
  5. Initialiser

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • la version de l’outil client NuGet
      • le langage effectif de l’outil client NuGet. Cela prend en compte le paramètre ForceEnglishOutput, s’il est utilisé.
      • le délai d’expiration de la requête par défaut, qui remplace le protocole par défaut.
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération. Une défaillance entraîne l’arrêt du plug-in.
  6. Journal

    • Direction de la requête : plug-in – NuGet >
    • La requête contient les éléments suivants :
      • le niveau de journal pour la demande
      • un message à enregistrer
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération.
  7. Surveiller la sortie du processus NuGet

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • l’identifiant du processus NuGet
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération.
  8. Package de prérécupération

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • la version et l’identifiant du package
      • l’emplacement du référentiel source du package
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
  9. Définir les informations d’identification

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • l’emplacement du référentiel source du package
      • le dernier nom d’utilisateur source du package connu, le cas échéant
      • le dernier mot de passe source du package connu, le cas échéant
      • le dernier nom d’utilisateur proxy connu, le cas échéant
      • le dernier mot de passe proxy connu, le cas échéant
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
  10. Définir niveau de journal

    • Direction de la requête : NuGet – plug-in >
    • La requête contient les éléments suivants :
      • le niveau de journal par défaut
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération

Messages de la version 2.0.0 du protocole

  1. Obtenir les revendications d’opération
  • Direction de la requête : NuGet – plug-in >

    • La requête contient les éléments suivants :
      • le service index.json pour une source de package
      • l’emplacement du référentiel source du package
    • Une réponse contiendra :
      • un code de réponse indiquant le résultat de l’opération
      • un énumérable des opérations prises en charge si l’opération a réussi. Si un plug-in ne prend pas en charge la source du package, le plug-in doit retourner un ensemble vide d’opérations prises en charge.

    Si l’index de service et la source du package sont null, le plug-in peut répondre avec l’authentification.

  1. Obtenir les informations d’identification d’authentification
  • Direction de la requête : NuGet – plug-in >
  • La requête contient les éléments suivants :
    • Uri
    • isRetry
    • NonInteractive
    • CanShowDialog
  • Une réponse contiendra :
    • Nom d’utilisateur
    • Mot de passe
    • Message
    • Liste des types d’authentification
    • MessageResponseCode