SolimusWrapper 1.0.0
There is a newer version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package SolimusWrapper --version 1.0.0
NuGet\Install-Package SolimusWrapper -Version 1.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SolimusWrapper" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SolimusWrapper" Version="1.0.0" />
<PackageReference Include="SolimusWrapper" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SolimusWrapper --version 1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: SolimusWrapper, 1.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SolimusWrapper@1.0.0
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SolimusWrapper&version=1.0.0
#tool nuget:?package=SolimusWrapper&version=1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
SolimusWrapper
Лёгкая и оптимизированная библиотека для работы с CLI процессами в .NET. Простой и интуитивный API для запуска внешних команд с поддержкой перенаправления потоков, таймаутов, отмены и кросс-платформенной работы.
🚀 Особенности
- Fluent API — читаемый и удобный синтаксис
- Immutable — каждый вызов создаёт новый экземпляр команды
- Асинхронность — полная поддержка async/await и CancellationToken
- Перенаправление потоков — stdout, stderr, stdin
- Таймауты — автоматическое завершение процессов
- Кросс-платформенность — Windows, Linux, macOS
- Оптимизация памяти — использование ArrayPool, ValueTask
- Native AOT — поддержка trimming
- Zero Dependencies — никаких внешних зависимостей
📁 Структура проекта
SolimusWrapper/
├── README.md # Главная документация
├── LICENSE # MIT License
├── SolimusWrapper.sln # Solution файл
│
├── src/
│ └── SolimusWrapper.Core/ # 📦 Основная библиотека
│ ├── README.md
│ ├── SolimusWrapper.Core.csproj
│ ├── Command.cs
│ ├── CommandResult.cs
│ ├── CommandExtensions.cs
│ ├── PipeTarget.cs
│ ├── PipeSource.cs
│ ├── Optional.cs
│ └── Builders/
│ └── CommandBuilder.cs
│
├── samples/
│ └── SolimusWrapper.Demo/ # 🎮 Примеры использования
│ ├── README.md
│ ├── SolimusWrapper.Demo.csproj
│ └── Program.cs
│
└── tests/
└── SolimusWrapper.Tests/ # 🧪 Unit-тесты
├── README.md
├── SolimusWrapper.Tests.csproj
├── CommandTests.cs
├── CommandBuilderTests.cs
├── CommandResultTests.cs
├── PipeTargetTests.cs
├── PipeSourceTests.cs
└── Fixtures/
└── TestHelper.cs
| Проект | Тип | Описание |
|---|---|---|
SolimusWrapper.Core |
Class Library | Ядро библиотеки (NuGet пакет) |
SolimusWrapper.Demo |
Console App | Примеры использования |
SolimusWrapper.Tests |
xUnit Tests | Unit-тесты |
📦 Установка
dotnet add package SolimusWrapper
Или через Package Manager:
Install-Package SolimusWrapper
🎯 Быстрый старт
using SolimusWrapper;
// Простой запуск команды
var result = await Command.Run("dotnet")
.WithArguments("--version")
.ExecuteAsync();
Console.WriteLine($"Exit code: {result.ExitCode}");
// Получить вывод команды
var output = await Command.Run("git")
.WithArguments("status")
.ExecuteAndReadOutputAsync();
Console.WriteLine(output);
📖 Использование
Базовые операции
// Запуск с аргументами
await Command.Run("dotnet")
.WithArguments("build", "-c", "Release")
.ExecuteAsync();
// Аргументы как коллекция
var args = new[] { "test", "--no-build", "--logger", "console" };
await Command.Run("dotnet")
.WithArguments(args)
.ExecuteAsync();
Получение вывода
// Только stdout
var stdout = await Command.Run("echo")
.WithArguments("Hello, World!")
.ExecuteAndReadOutputAsync();
// stdout и stderr отдельно
var (stdOut, stdErr) = await Command.Run("dotnet")
.WithArguments("build")
.ExecuteAndReadAllAsync();
Перенаправление потоков
var output = new StringBuilder();
var errors = new StringBuilder();
await Command.Run("dotnet")
.WithArguments("build")
.WithStandardOutputPipe(PipeTarget.ToStringBuilder(output))
.WithStandardErrorPipe(PipeTarget.ToStringBuilder(errors))
.ExecuteAsync();
Вывод в реальном времени
await Command.Run("dotnet")
.WithArguments("test")
.WithStandardOutputPipe(PipeTarget.ToDelegate(line =>
Console.WriteLine($"[OUT] {line}")))
.WithStandardErrorPipe(PipeTarget.ToDelegate(line =>
Console.WriteLine($"[ERR] {line}")))
.ExecuteAsync();
Запись в файл
await Command.Run("dotnet")
.WithArguments("build", "-v", "detailed")
.WithStandardOutputPipe(PipeTarget.ToFile("build.log"))
.ExecuteAsync();
Передача данных в stdin
// Из строки
await Command.Run("grep")
.WithArguments("error")
.WithStandardInputPipe(PipeSource.FromString("line1\nerror here\nline3"))
.ExecuteAsync();
// Из файла
await Command.Run("cat")
.WithStandardInputPipe(PipeSource.FromFile("input.txt"))
.ExecuteAsync();
// Из потока
using var stream = File.OpenRead("data.bin");
await Command.Run("processor")
.WithStandardInputPipe(PipeSource.FromStream(stream))
.ExecuteAsync();
Рабочая директория
await Command.Run("npm")
.WithArguments("install")
.WithWorkingDirectory("/path/to/project")
.ExecuteAsync();
Переменные окружения
await Command.Run("node")
.WithArguments("app.js")
.WithEnvironmentVariable("NODE_ENV", "production")
.WithEnvironmentVariable("PORT", "3000")
.ExecuteAsync();
// Несколько переменных сразу
var envVars = new Dictionary
{
["API_KEY"] = "secret",
["DEBUG"] = "true"
};
await Command.Run("myapp")
.WithEnvironmentVariables(envVars)
.ExecuteAsync();
Таймауты
try
{
await Command.Run("long-process")
.WithTimeout(TimeSpan.FromSeconds(30))
.ExecuteAsync();
}
catch (TimeoutException)
{
Console.WriteLine("Процесс превысил лимит времени");
}
Отмена операции
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
try
{
await Command.Run("long-task")
.ExecuteAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Операция отменена");
}
Обработка кодов выхода
// По умолчанию выбрасывает исключение при ненулевом коде
try
{
await Command.Run("failing-command").ExecuteAsync();
}
catch (CommandExecutionException ex)
{
Console.WriteLine($"Команда завершилась с кодом: {ex.ExitCode}");
}
// Отключить проверку
var result = await Command.Run("might-fail")
.WithValidation(false)
.ExecuteAsync();
if (!result.IsSuccess)
{
Console.WriteLine($"Exit code: {result.ExitCode}");
}
Callback при завершении
await Command.Run("task")
.OnExit(exitCode =>
{
if (exitCode != 0)
Console.WriteLine($"Warning: exit code {exitCode}");
})
.WithValidation(false)
.ExecuteAsync();
Кодировка
using System.Text;
// Для Windows консоли (кириллица)
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
await Command.Run("cmd")
.WithArguments("/c", "dir")
.WithEncoding(Encoding.GetEncoding(866))
.ExecuteAsync();
🔨 CommandBuilder
Альтернативный способ построения команд с условной логикой:
using SolimusWrapper.Builders;
var verbose = true;
var configuration = "Release";
var result = await new CommandBuilder("dotnet")
.AddArgument("build")
.AddFlag("--no-restore")
.AddFlag("-v", verbose)
.AddArgumentIfNotEmpty("-c", configuration)
.AddArgumentIf(Environment.OSVersion.Platform == PlatformID.Unix, "--runtime", "linux-x64")
.SetWorkingDirectory("/path/to/project")
.SetTimeout(TimeSpan.FromMinutes(10))
.SetStandardOutput(Console.WriteLine)
.ExecuteAsync();
Методы CommandBuilder
| Метод | Описание |
|---|---|
SetTarget(string) |
Устанавливает исполняемый файл |
AddArgument(string) |
Добавляет один аргумент |
AddArgument(string, string) |
Добавляет аргумент с значением |
AddArguments(params string[]) |
Добавляет несколько аргументов |
AddArgumentIf(bool, string) |
Условное добавление аргумента |
AddArgumentIfNotEmpty(string, string?) |
Добавляет если значение не пустое |
AddFlag(string, bool) |
Добавляет флаг если enabled = true |
ClearArguments() |
Очищает все аргументы |
SetWorkingDirectory(string) |
Устанавливает рабочую директорию |
SetEnvironmentVariable(string, string?) |
Добавляет переменную окружения |
SetStandardOutput(StringBuilder) |
Перенаправляет stdout в StringBuilder |
SetStandardOutput(Action<string>) |
Перенаправляет stdout в делегат |
SetStandardError(StringBuilder) |
Перенаправляет stderr в StringBuilder |
MergeStandardOutputAndError(PipeTarget) |
Объединяет stdout и stderr |
SetStandardInput(string) |
Устанавливает stdin |
SetEncoding(Encoding) |
Устанавливает кодировку |
SetValidation(bool) |
Включает/выключает проверку exit code |
SetTimeout(TimeSpan) |
Устанавливает таймаут |
OnExit(Action<int>) |
Callback при завершении |
Build() |
Создаёт объект Command |
ExecuteAsync() |
Строит и выполняет команду |
🌐 Кросс-платформенные хелперы
using SolimusWrapper;
// Shell команда (cmd на Windows, sh на Unix)
var result = await CommandExtensions.Shell("echo Hello").ExecuteAndReadOutputAsync();
// Список файлов
var files = await CommandExtensions.ListFiles().ExecuteAndReadOutputAsync();
var files2 = await CommandExtensions.ListFiles("/path/to/dir").ExecuteAndReadOutputAsync();
// Текущая директория
var pwd = await CommandExtensions.GetCurrentDirectory().ExecuteAndReadOutputAsync();
// Echo
await CommandExtensions.Echo("Hello, World!").ExecuteAsync();
// Sleep
await CommandExtensions.Sleep(5).ExecuteAsync();
// Ping
await CommandExtensions.Ping("google.com", count: 4)
.WithStandardOutputPipe(PipeTarget.ToDelegate(Console.WriteLine))
.ExecuteAsync();
// Переменная окружения
var path = await CommandExtensions.GetEnvironmentVariable("PATH").ExecuteAndReadOutputAsync();
// Поиск файлов
var found = await CommandExtensions.FindFiles("*.cs", "/path/to/search").ExecuteAndReadOutputAsync();
// Проверка существования файла
var exists = await CommandExtensions.FileExists("myfile.txt").ExecuteAndReadOutputAsync();
📊 API Reference
Command
| Метод | Описание |
|---|---|
Run(string) |
Создаёт новую команду |
WithArguments() |
Устанавливает аргументы |
WithWorkingDirectory() |
Устанавливает рабочую директорию |
WithEnvironmentVariable() |
Добавляет переменную окружения |
WithEnvironmentVariables() |
Добавляет несколько переменных |
WithStandardOutputPipe() |
Перенаправляет stdout |
WithStandardErrorPipe() |
Перенаправляет stderr |
WithStandardInputPipe() |
Устанавливает stdin |
WithEncoding() |
Устанавливает кодировку |
WithValidation() |
Включает/выключает проверку exit code |
WithTimeout() |
Устанавливает таймаут |
OnExit() |
Callback при завершении |
ExecuteAsync() |
Выполняет команду |
ExecuteAndReadOutputAsync() |
Выполняет и возвращает stdout |
ExecuteAndReadAllAsync() |
Выполняет и возвращает stdout + stderr |
PipeTarget
| Метод | Описание |
|---|---|
Null |
Отбрасывает вывод |
ToStringBuilder(sb) |
В StringBuilder |
ToDelegate(action) |
Вызывает action для каждой строки |
ToStream(stream) |
В поток |
ToFile(path) |
В файл |
PipeSource
| Метод | Описание |
|---|---|
Null |
Пустой ввод |
FromString(text) |
Из строки |
FromStream(stream) |
Из потока |
FromFile(path) |
Из файла |
FromBytes(data) |
Из массива байтов |
CommandResult
| Свойство/Метод | Описание |
|---|---|
ExitCode |
Код выхода процесса |
IsSuccess |
true если ExitCode == 0 |
StartTime |
Время запуска |
ExitTime |
Время завершения |
RunTime |
Длительность выполнения |
EnsureSuccess() |
Выбрасывает исключение если ExitCode != 0 |
🧪 Примеры
Git операции
// Статус репозитория
var status = await Command.Run("git")
.WithArguments("status", "--short")
.WithWorkingDirectory("/path/to/repo")
.ExecuteAndReadOutputAsync();
// Коммит
await Command.Run("git")
.WithArguments("commit", "-m", "feat: add new feature")
.ExecuteAsync();
// Pull с таймаутом
await Command.Run("git")
.WithArguments("pull", "--rebase")
.WithTimeout(TimeSpan.FromMinutes(2))
.ExecuteAsync();
Docker
// Запуск контейнера
await Command.Run("docker")
.WithArguments("run", "--rm", "-d", "-p", "8080:80", "nginx")
.ExecuteAsync();
// Логи контейнера
await Command.Run("docker")
.WithArguments("logs", "-f", "my-container")
.WithStandardOutputPipe(PipeTarget.ToDelegate(Console.WriteLine))
.WithTimeout(TimeSpan.FromSeconds(30))
.ExecuteAsync();
// Docker Compose
await Command.Run("docker-compose")
.WithArguments("up", "-d")
.WithWorkingDirectory("/path/to/project")
.WithEnvironmentVariable("COMPOSE_PROJECT_NAME", "myapp")
.ExecuteAsync();
.NET CLI
// Сборка проекта
var buildOutput = new StringBuilder();
var result = await Command.Run("dotnet")
.WithArguments("build", "-c", "Release", "--no-restore")
.WithStandardOutputPipe(PipeTarget.ToStringBuilder(buildOutput))
.WithWorkingDirectory("/path/to/solution")
.ExecuteAsync();
if (result.IsSuccess)
{
Console.WriteLine("Build succeeded!");
Console.WriteLine(buildOutput);
}
// Запуск тестов
await Command.Run("dotnet")
.WithArguments("test", "--logger", "console;verbosity=detailed")
.WithStandardOutputPipe(PipeTarget.ToDelegate(line =>
{
if (line.Contains("Passed") || line.Contains("Failed"))
Console.WriteLine(line);
}))
.ExecuteAsync();
// Публикация
await new CommandBuilder("dotnet")
.AddArgument("publish")
.AddArgument("-c", "Release")
.AddArgument("-o", "./publish")
.AddFlag("--self-contained")
.AddArgumentIf(OperatingSystem.IsLinux(), "-r", "linux-x64")
.AddArgumentIf(OperatingSystem.IsWindows(), "-r", "win-x64")
.ExecuteAsync();
FFmpeg
// Конвертация видео
await Command.Run("ffmpeg")
.WithArguments(
"-i", "input.mp4",
"-c:v", "libx264",
"-crf", "23",
"-c:a", "aac",
"-b:a", "128k",
"output.mp4")
.WithStandardErrorPipe(PipeTarget.ToDelegate(Console.WriteLine))
.WithTimeout(TimeSpan.FromHours(1))
.ExecuteAsync();
// Извлечение аудио
await Command.Run("ffmpeg")
.WithArguments("-i", "video.mp4", "-vn", "-acodec", "mp3", "audio.mp3")
.ExecuteAsync();
npm / Node.js
// Установка зависимостей
await Command.Run("npm")
.WithArguments("install")
.WithWorkingDirectory("/path/to/frontend")
.WithEnvironmentVariable("NODE_ENV", "development")
.ExecuteAsync();
// Запуск скрипта
await Command.Run("npm")
.WithArguments("run", "build")
.WithStandardOutputPipe(PipeTarget.ToDelegate(Console.WriteLine))
.ExecuteAsync();
⚡ Оптимизации
Библиотека оптимизирована для производительности:
| Аспект | Реализация |
|---|---|
| Memory | ArrayPool<char> для буферов чтения |
| ValueTask | Меньше аллокаций для sync-path |
| Record struct | CommandResult размещается на стеке |
| file sealed | Внутренние классы скрыты от API |
| Trimming | Полная поддержка Native AOT |
🛠️ Сборка из исходников
# Клонировать репозиторий
git clone https://github.com/yourname/SolimusWrapper.git
cd SolimusWrapper
# Восстановить зависимости
dotnet restore
# Собрать
dotnet build
# Запустить тесты
dotnet test
# Запустить демо
dotnet run --project samples/SolimusWrapper.Demo
# Создать NuGet пакет
dotnet pack -c Release
📄 Лицензия
MIT License. См. LICENSE для подробностей.
🤝 Contributing
Contributions welcome! Пожалуйста, создайте issue или pull request.
- Fork репозитория
- Создайте feature branch (
git checkout -b feature/amazing-feature) - Commit изменения (
git commit -m 'Add amazing feature') - Push в branch (
git push origin feature/amazing-feature) - Откройте Pull Request
📞 Связь
- GitHub Issues: Issues
- Email: salawat1302@gmail.com
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.