- PVSM.RU - https://www.pvsm.ru -
Пару недель назад вышел .NET Core 2.1 RC1 [1]. Это первая версия SDK, где есть фича под названием "Глобальные утилиты .NET Core" (".NET Core Global Tools"). Она дает простой способ создания кросс-платформенных консольных утилит.

Мы познакомимся с основами использования .NET Core Global Tools и кратко посмотрим, что внутри. А еще вы можете скачать .NET Core 2.1 SDK [2] и попробовать написать собственный пример.
.NET Core global tool — это специальный пакет NuGet, в котором находится консольное приложение. Когда вы устанавливаете его, .NET Core CLI скачивает пакет и делает его доступным в виде новой глобальной консольной команды.
Пользователи могут устанавливать утилиты с помощью команды dotnet tool install:
dotnet tool install -g <nuget package name>
После установки консольные утилиты, находящиеся в пакете, будут глобально доступны по имени:
<command name>
dotnet tool имеет и другие команды. Например:
dotnet tool list -g
dotnet tool uninstall -g <nuget package name>
dotnet tool update -g <nuget package name>
NuGet пакет с консольной утилитой содержит все файлы, полученные в результате выполнения команды dotnet publish, а также несколько дополнительных файлов с мета-информацией.
Когда вы запускаете dotnet tool install --global, происходит следующее:
dotnet restore со специальными параметрами [3], чтобы скачать пакет.$HOME/.dotnet/.store/<package id>/<version>.$HOME/.dotnet/tools.Сгенерированный запускаемый файл — это небольшое консольное приложение (написанное на C++ [4]), которое знает, где находится ваш .NET Core DLL файл и автоматически запускает его.
Вы также можете запустить dotnet tool install с аргументом --tool-path $installDir. Эта команда делает всё то же самое, но устанавливает консольное приложение в папку $installDir, а не в $HOME/.dotnet/tools.
Для создания глобальных консольных утилит вам нужен .NET Core SDK версии 2.1 [2]. В этой версии добавлено несколько дополнительных настроек проектов для управления неймингом и содержимым пакетов с глобальными консольными утилитами.
Минимальные необходимые параметры проекта:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackAsTool>true</PackAsTool>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
</Project>
Дополнительные (не обязательные) параметры, управляющие сборкой пакета:
AssemblyName — задает название .dll файла вашего консольного приложения.ToolCommandName — название команды, по которому пользователь будет запускать вашу консольную утилиту. По умолчанию оно совпадает с названием .dll файла (которое задано в параметре AssemblyName).
dotnet-. Можно использовать любое название без пробелов.dotnet-, то утилиту можно будет запускать как команду утилиты dotnet (убедитесь, что команды с таким именем еще нет). Например, утилита dotnet-say-moo может быть вызвана и как dotnet-say-moo, и как dotnet say-moo.PackageId — идентификатор NuGet пакета. По умолчанию совпадает с названием .csproj файла. Этот идентификатор нужно указывать при установке. При этом он может отличаться от названия команды (ToolCommandName) и названия .dll файла (AssemblyName).PackageVersion — версия NuGet пакета (по умолчанию 1.0.0). Также вместо PackageVersion можно использовать VersionPrefix и VersionSuffix.Пример использования этих параметров:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackAsTool>true</PackAsTool>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<ToolCommandName>pineapple</ToolCommandName>
<PackageId>dole-cli</PackageId>
<PackageVersion>1.0.0-alpha-$(BuildNumber)</PackageVersion>
<AssemblyName>Dole.Cli</AssemblyName>
</PropertyGroup>
</Project>
Сборка пакета происходит как обычно — при помощи команды dotnet pack. SDK увидит, что установлен параметр PackAsTool=true и автоматически сгенерирует нужные дополнительные файлы.
dotnet pack --output ./packages
С помощью параметра --source-feed вы можете установить пакет, который еще не опубликован в репозитории пакетов NuGet. Это может быт ьполезно для проверки, что всё сделано правильно. Также, если версия пакета — не релизная (например, 3.0.0-alpha — содержит что-то, кроме трех чисел), нужно при установке явно указать её.
Например:
dotnet tool install -g my-package-name --version 3.0.0-alpha --source-feed ./packages/
Как я писал выше, команда dotnet pack собирает пакет особым образом, если в файле проекта указан параметр PackAsTool=true.
В пакет попадают не только файлы, полученные через dotnet build, но и все другие зависимости вашего проекта (подключенные сторонние пакеты NuGet). Все файлы, необходимые для работы вашей консольной утилиты, должны быть включены в NuGet пакет. Команда dotnet-tool-install не устанавливает зависимости, указанные в резделе <dependencies> вашего .nuspec файла.
Генерируется специальный файл DotnetToolSettings.xml, который содержит информацию о вашем консольном приложении. Если этого файла по какой-то причине не окажется в пакете (например, пытаетесь установить произвольный пакет как консольную утилиту), то при установке вы получите ошибку:
The settings file in the tool’s NuGet package is invalid: Settings file ‘DotnetToolSettings.xml’ was not found in the package.
Пример содержимого файла:
<DotNetCliTool Version="1">
<Commands>
<Command Name="my-command-name" EntryPoint="my-file.dll" Runner="dotnet" />
</Commands>
</DotNetCliTool>
Сейчас есть следующие требования к файлу DotnetToolSettings.xml:
DotnetToolSettings.xml должен находиться в папке tools/$targetframework/any/. Например: tools/netcoreapp2.1/any/DotnetToolSettings.xml.DotnetToolSettings.xml.DotnetToolSettings.xml должна быть описана только одна секция <Command>.Runner должно быть "dotnet".EntryPoint должно быть указано название .dll файла, который лежит в одной папке с файлом DotnetToolSettings.xml.В .nuspec файл автоматически добавляется параметр <packageType name="DotnetTool" />. Например:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<!-- Следующий фрагмент обязательно должен быть! -->
<packageTypes>
<packageType name="DotnetTool" />
</packageTypes>
<!-- ... -->
</metadata>
</package>
Если параметр packageType[name] не указан как DotnetTool, то при установке получите ошибку:
error NU1212: Invalid project-package combination for awesome-tool 1.0.0. DotnetToolReference project style can only contain references of the DotnetTool type
Конечно, это не очень понятное сообщение об ошибке. На Github есть issue [5], чтобы это улучить.
.NET Core CLI по умолчанию устанавливает глобальные утилиты в папку $HOME/.dotnet/tools (на Linux/macOS) или в папку %USERPROFILE%.dotnettools (на Windows). Это значит, что вы не можете установить пакет глобально для всех пользователей компьютера с помощью dotnet tool install --global. Установленные утилиты доступы только для пользователя, который их установил.
Обычно .NET Core автоматически добавляет путь к папке с установленными утилитами в переменную окружения PATH, чтобы они были доступны по имени, без указания полного пути. Но иногда это может не сработать. Например:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE (например, чтобы ускорить первый запуск .NET Core), то значение переменной PATH может быть не установлено при первом использовании.tar.gz файла (а не из .pkg файла), то у вас может не быть файла /etc/paths.d/dotnet-cli-tool который настраивает переменную PATH.~/.bash_profile или ~/.zshrcВ этом случае при запуске своей консолььной утилиты вы получите ошибку. Например:
bash: my-command-name: command not found
Чтобы всё заработало, нужно добавить в переменную PATH путь к папке с утилитами. Например так (после добавления нужно перезапустить терминал):
cat << EOF >> ~/.bash_profile
# Add .NET Core SDK tools
export PATH="$PATH:/Users/<user-name>/.dotnet/tools"
EOF
Или вот так можно добавить для текущей сессии:
export PATH="$PATH:/Users/<user-name>/.dotnet/tools"
Примеры выше — для MacOS. Для других систем всё аналогично. Кроме того, при установке вашей глобальной консольной утилиты команда dotnet tool install проверит, что переменная PATH правильно настроена и предложит варианты решения, если это не так.
Если вы скачали .NET Core CLI как .zip/.tar.gz архив и распаковали его в папку, которая отличается от папки по умолчанию, то при запуске своей консольной утилиты вы можете получить ошибку:
A fatal error occurred, the required library hostfxr.dll could not be foundA fatal error occurred, the required library libhostfxr.so could not be foundA fatal error occurred, the required library libhostfxr.dylib could not be foundВ сообщении об ошибке будет также дополнительная информация:
If this is a self-contained application, that library should exist in [some path here].
If this is a framework-dependent application, install the runtime in the default location [default location] or use the DOTNET_ROOT environment variable to specify the runtime location.
Причина в том, что запускаемы файл, который генерируется командой dotnet tool install при установке пакета, ищет .NET Core в папке по умолчанию. Вы можете переопределить пути по умолчанию, установив переменную окружения DOTNET_ROOT. Например:
# Windows
set DOTNET_ROOT=C:Usersusernamedotnet
# MacOS/Linux
export DOTNET_ROOT=/Users/username/Downloads/dotnet
Подробности в issue [6] на GitHub.
Мы познакомились с глобальными консольными утилитами в .NET Core. На мой взгляд, это очень крутая штука. Я крайне счастлив, что команда .NET Core её запилила. Не могу дождаться, когда все начнут её использовать :)
Автор: Дмитрий Андриянов
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/net/280636
Ссылки в тексте:
[1] вышел .NET Core 2.1 RC1: https://blogs.msdn.microsoft.com/dotnet/2018/05/07/announcing-net-core-2-1-rc-1/
[2] скачать .NET Core 2.1 SDK: https://aka.ms/DotNetCore21
[3] специальными параметрами: https://github.com/dotnet/cli/pull/8414
[4] написанное на C++: https://github.com/dotnet/core-setup/tree/release/2.1/src/corehost/cli/exe/apphost
[5] issue: https://github.com/NuGet/Home/issues/6630
[6] issue: https://github.com/dotnet/cli/issues/9114
[7] Источник: https://habr.com/post/359006/?utm_source=habrahabr&utm_medium=rss&utm_campaign=359006
Нажмите здесь для печати.