Repository: mayuki/Chell
Branch: main
Commit: 79e25d9b187a
Files: 57
Total size: 200.3 KB
Directory structure:
gitextract_m746u3r_/
├── .editorconfig
├── .gitattributes
├── .github/
│ └── workflows/
│ ├── build.yaml
│ └── release.yaml
├── .gitignore
├── Chell.sln
├── Directory.Build.props
├── LICENSE
├── README.md
├── samples/
│ ├── GettingStarted.Basic.Unix/
│ │ ├── GettingStarted.Basic.Unix.csproj
│ │ └── Program.cs
│ └── GettingStarted.Basic.Windows/
│ ├── GettingStarted.Basic.Windows.csproj
│ └── Program.cs
├── src/
│ ├── .editorconfig
│ ├── Chell/
│ │ ├── Chell.csproj
│ │ ├── ChellEnvironment.cs
│ │ ├── CommandLineString.cs
│ │ ├── Exports.cs
│ │ ├── Extensions/
│ │ │ ├── ChellExtensions.cs
│ │ │ ├── ProcessOutputExtensions.cs
│ │ │ ├── ProcessTaskExtensions.Generated.cs
│ │ │ ├── ProcessTaskExtensions.cs
│ │ │ ├── ProcessTaskExtensions.tt
│ │ │ └── StringExtensions.cs
│ │ ├── IO/
│ │ │ ├── ChellWrappedStream.cs
│ │ │ ├── ChellWritableStream.Generated.cs
│ │ │ ├── ChellWritableStream.tt
│ │ │ ├── IConsoleProvider.cs
│ │ │ ├── LINQPadConsoleProvider.cs
│ │ │ └── SystemConsoleProvider.cs
│ │ ├── Internal/
│ │ │ ├── CommandLineHelper.cs
│ │ │ ├── EnvironmentVariables.cs
│ │ │ ├── LINQPadHelper.cs
│ │ │ ├── ObjectDumper.cs
│ │ │ ├── OutputSink.cs
│ │ │ ├── StandardInput.cs
│ │ │ ├── StreamPipe.cs
│ │ │ └── Which.cs
│ │ ├── ProcessOutput.cs
│ │ ├── ProcessTask.cs
│ │ ├── ProcessTaskException.cs
│ │ ├── ProcessTaskOptions.cs
│ │ ├── Run.cs
│ │ └── Shell/
│ │ ├── BashShellExecutor.cs
│ │ ├── CmdShellExecutor.cs
│ │ ├── IShellExecutor.cs
│ │ ├── NoUseShellExecutor.cs
│ │ └── ShellExecutorProvider.cs
│ └── Chell.Run/
│ ├── Chell.Run.csproj
│ └── Program.cs
└── tests/
└── Chell.Tests/
├── Chell.Tests.csproj
├── ChellEnvironmentTest.cs
├── CommandLineStringTest.cs
├── ProcessTaskTest.cs
├── Shell/
│ ├── BashShellExecutorTest.cs
│ └── CmdShellExecutorTest.cs
└── TemporaryAppBuilder.cs
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
###############################
# Core EditorConfig Options #
###############################
root = true
# All files
[*]
indent_style = space
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
insert_final_newline = true
charset = utf-8
[*.md]
charset = utf-8
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = true
# this. preferences
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
###############################
# C# Coding Conventions #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
*.sh text eol=lf
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
================================================
FILE: .github/workflows/build.yaml
================================================
name: Build-Development
on:
push:
branches:
- main
- master
pull_request:
types:
- opened
- synchronize
jobs:
Build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
env:
DOTNET_NOLOGO: true
steps:
- uses: actions/checkout@v1
- uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.x'
# Build
- run: dotnet restore
- run: dotnet build -c Release
# Run Unit tests
- run: dotnet test -c Release --no-build --logger trx --results-directory $GITHUB_WORKSPACE/artifacts
# Packaging
- name: dotnet pack
run: dotnet pack -c Release --no-build -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg --output $GITHUB_WORKSPACE/artifacts
shell: bash
# Upload & Publish
- uses: actions/upload-artifact@master
with:
name: Packages
path: artifacts
================================================
FILE: .github/workflows/release.yaml
================================================
name: Build-Release
on:
push:
tags:
- v*
jobs:
Release:
if: "contains(github.ref, 'refs/tags')"
runs-on: ubuntu-latest
env:
DOTNET_NOLOGO: true
steps:
- uses: actions/checkout@v1
- uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.x'
- name: "Set VersionSuffix for Preview"
if: "contains(github.ref, 'refs/tags') && contains(github.ref, 'preview')"
run: |
echo "VERSION_SUFFIX=preview.`date '+%Y%m%d-%H%M%S'`+${GITHUB_SHA:0:6}" >> $GITHUB_ENV
- name: "Get git tag"
if: "contains(github.ref, 'refs/tags')"
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
# Build
- run: dotnet restore
- run: dotnet build -c Release
# Packaging
- name: dotnet pack
run: dotnet pack -c Release --no-build --version-suffix "$VERSION_SUFFIX" -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg --output $GITHUB_WORKSPACE/artifacts
# Upload & Publish
- uses: actions/upload-artifact@master
with:
name: Packages
path: artifacts
- name: "Push to NuGet.org"
run: |
dotnet nuget push "$GITHUB_WORKSPACE/artifacts/*.nupkg" --skip-duplicate -k ${{ secrets.NUGET_KEY }} -s https://api.nuget.org/v3/index.json
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
.DS_Store
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# .NET Launch Profiles
launchSettings.json
================================================
FILE: Chell.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chell", "src\Chell\Chell.csproj", "{6BE659EC-A00D-4148-B19D-B5478DE001FA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chell.Run", "src\Chell.Run\Chell.Run.csproj", "{893D8C70-3C13-47D6-987F-C099C6161D7E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chell.Tests", "tests\Chell.Tests\Chell.Tests.csproj", "{1FBAA8ED-438E-498C-AB1F-29429550DC21}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EBB92712-D878-48FD-8E31-E577AABDC0FB}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
.github\workflows\build.yaml = .github\workflows\build.yaml
Directory.Build.props = Directory.Build.props
README.md = README.md
.github\workflows\release.yaml = .github\workflows\release.yaml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{AF454F92-8B84-446B-B0E2-9BA8887B09CC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GettingStarted.Basic.Windows", "samples\GettingStarted.Basic.Windows\GettingStarted.Basic.Windows.csproj", "{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GettingStarted.Basic.Unix", "samples\GettingStarted.Basic.Unix\GettingStarted.Basic.Unix.csproj", "{69DC1056-843E-4980-908A-5DB4ADA95460}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Debug|x64.ActiveCfg = Debug|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Debug|x64.Build.0 = Debug|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Debug|x86.ActiveCfg = Debug|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Debug|x86.Build.0 = Debug|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Release|Any CPU.Build.0 = Release|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Release|x64.ActiveCfg = Release|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Release|x64.Build.0 = Release|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Release|x86.ActiveCfg = Release|Any CPU
{6BE659EC-A00D-4148-B19D-B5478DE001FA}.Release|x86.Build.0 = Release|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Debug|x64.ActiveCfg = Debug|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Debug|x64.Build.0 = Debug|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Debug|x86.ActiveCfg = Debug|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Debug|x86.Build.0 = Debug|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Release|Any CPU.Build.0 = Release|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Release|x64.ActiveCfg = Release|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Release|x64.Build.0 = Release|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Release|x86.ActiveCfg = Release|Any CPU
{893D8C70-3C13-47D6-987F-C099C6161D7E}.Release|x86.Build.0 = Release|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Debug|x64.ActiveCfg = Debug|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Debug|x64.Build.0 = Debug|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Debug|x86.ActiveCfg = Debug|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Debug|x86.Build.0 = Debug|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Release|Any CPU.Build.0 = Release|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Release|x64.ActiveCfg = Release|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Release|x64.Build.0 = Release|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Release|x86.ActiveCfg = Release|Any CPU
{1FBAA8ED-438E-498C-AB1F-29429550DC21}.Release|x86.Build.0 = Release|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Debug|x64.ActiveCfg = Debug|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Debug|x64.Build.0 = Debug|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Debug|x86.ActiveCfg = Debug|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Debug|x86.Build.0 = Debug|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Release|Any CPU.Build.0 = Release|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Release|x64.ActiveCfg = Release|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Release|x64.Build.0 = Release|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Release|x86.ActiveCfg = Release|Any CPU
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5}.Release|x86.Build.0 = Release|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Debug|Any CPU.Build.0 = Debug|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Debug|x64.ActiveCfg = Debug|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Debug|x64.Build.0 = Debug|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Debug|x86.ActiveCfg = Debug|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Debug|x86.Build.0 = Debug|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Release|Any CPU.ActiveCfg = Release|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Release|Any CPU.Build.0 = Release|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Release|x64.ActiveCfg = Release|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Release|x64.Build.0 = Release|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Release|x86.ActiveCfg = Release|Any CPU
{69DC1056-843E-4980-908A-5DB4ADA95460}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9BE2CB2C-D6F2-429A-A00F-CF30CAEF28B5} = {AF454F92-8B84-446B-B0E2-9BA8887B09CC}
{69DC1056-843E-4980-908A-5DB4ADA95460} = {AF454F92-8B84-446B-B0E2-9BA8887B09CC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5B16EB0E-5342-4D93-9FA2-8327FF69A276}
EndGlobalSection
EndGlobal
================================================
FILE: Directory.Build.props
================================================
1.0.0
latest
enable
true
$(NoWarn);1591;1587;1574
Write scripts with the power of .NET. Provides a shell script-like (bash, cmd, ...) experience to .NET application.
Mayuki Sawatari
Copyright © Mayuki Sawatari
https://github.com/mayuki/Chell
https://github.com/mayuki/Chell
CommandLine Shell Process
MIT
================================================
FILE: LICENSE
================================================
MIT License
Copyright © Mayuki Sawatari
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Chell
Write scripts with the power of C# and .NET.
Chell is a library and execution tool for providing a shell script-like (bash, cmd, ...) experience to .NET applications.
```csharp
var branch = await Run($"git branch --show-current");
await Run($"git archive {branch} -o {branch}.zip");
```
.NET applications are great for complex tasks, but executing processes can be boring. Chell brings the experience closer to shell scripting. This library is heavily influenced by [google/zx](https://github.com/google/zx).
## When should I use Chell?
- **Write better shell scripts**: Write a complex script and use the power of .NET and C#
- **Write multi-platform shell scripts**: As an alternative to scripts that work on multiple platforms
- **Run a process quickly in your app**: As .NET library for easy handling of process launch and output
- **All developers in the project are .NET developers**: 🙃
Of course, if the shell script is already working fine and you don't have any problems, then there is no need to use Chell.
## Chell at a glance
Using Chell makes the code feel more like a script by taking advantage of C# 9's top-level statements and C# 6's `using static`.
```csharp
// Chell.Exports exposes a variety of functions and properties
using Chell;
using static Chell.Exports;
```
```csharp
// Move the current directory with Cd method
Cd("/tmp");
// Dispose the return value of Cd method to return to the previous directory
using (Cd("/usr/local/bin"))
{
// The current directory is "/usr/local/bin".
}
// The current directory is "/" again.
```
```csharp
// You can run the process by passing a string to Run method
await Run($"ls -lFa");
```
```csharp
// An interpolated string passed to Run method will be escaped and expanded if it is an array
var newDirs = new [] { "foo", "bar", "my app", "your;app" };
await Run($"mkdir {newDirs}"); // $ mkdir foo bar "my app" "your;app"
```
```csharp
// Run method returns the result object of the command (ProcessOutput class)
var result = await Run($"ls -lFa");
// You can read stdout & stderr line by line
foreach (var line in result)
{
Echo(line);
}
// Allows to get stdout & stderr with implicit conversion to `string`
string output = result;
// You can also get stdout as bytes (ReadOnlyMemory)
var binary = result.OutputBinary;
```
```csharp
// Provides convenient extension methods for parsing JSON.
var images = await Run($"docker image ls --format {"{{json .}}"}").SuppressConsoleOutputs();
foreach (var image in images.AsJsonLines(new { Repository = "", ID = "", Tag = ""}))
{
Echo(image);
}
// $ docker image ls --format "{{json .}}"
// { Repository = mcr.microsoft.com/dotnet/sdk, ID = b160c8f3dbd6, Tag = 5.0 }
// { Repository = , ID = 3ee645b4a3bd, Tag = }
```
```csharp
// Standard input/output of process tasks can be connected by pipes
await (Run($"ls -lFa") | Run($"grep dotnet"));
// The difference with `await (Run($"ls -lFa | grep dotnet"));` is that the shell can pipe or not.
// You can also specify a Stream as input or output
// Write ffmpeg output to a Stream.
await (Run($"ffmpeg ...") | destinationStream);
// Write a Stream to ffmpeg process.
await (srcStream | Run($"ffmpeg ..."));
```
Just want to make it easy for your app to handle processes? If you don't use `Chell.Exports`, you won't get any unnecessary methods or properties, and you'll get the same functions by `new Run(...)`.
```csharp
using Chell;
var result = await new Run($"ls -lF");
```
Want to run it like a scripting language? Install [Chell.Run](#chellrun), and you can run it like a script.
```bash
% dotnet tool install -g Chell.Run
% chell -e "Echo(DateTime.Now)"
9/1/2021 0:00:00 PM
% cat <<__EOF__ > MyScript.cs
var dirs = new [] { "foo bar", "baz" };
await Run($"mkdir {dirs}");
await Run($"ls -l");
__EOF__
% chell MyScript.cs
$ mkdir "foo bar" "baz"
$ ls -l
total 8
drwxr-xr-x 2 mayuki mayuki 4096 Sep 1 00:00 baz/
drwxr-xr-x 2 mayuki mayuki 4096 Sep 1 00:00 'foo bar'/
```
## Features
- Automatic shell character escaping and array expansion
- Stream and Process Pipes
- Provide utilities and shortcuts useful for scripting.
- Simple shell script-like execution tools
- Multi-platform (Windows, Linux, macOS)
- LINQPad friendly
## Install
```
dotnet package add Chell
```
### Requirements
.NET Standard 2.1, .NET 5 or higher
## Chell.Exports
Chell.Exports class exposes a variety of utilities and shortcuts to make writing feel like shell scripting. It is recommended to include this class in your scripts with `static using`.
### Methods (Functions)
#### `Run`
Starts a process using the specified command-line and returns a `ProcessTask`.
```csharp
await Run($"ls -lF");
// The followings are equivalent to calling Run method
await (Run)$"ls -lF";
await new Run($"ls -lF");
```
The process will be launched asynchronously and can wait for completion by `await`. And you can `await` to get a `ProcessOutput` object with its output.
If the exit code of the process returns non-zero, it will throw an exception. To suppress this exception, see `NoThrow`.
An interpolated string passed to Run method will be escaped and expanded if it is an array.
```csharp
var newDirs = new [] { "foo", "bar", "my app", "your;app" };
await Run($"mkdir {newDirs}"); // equivalent to `mkdir foo bar "my app" "your;app"`
```
You can also pass an execution options (`ProcessTaskOptions`) to Run method.
```csharp
await Run($"ping -t localhost", new ProcessTaskOptions(
workingDirectory: @"C:\Windows",
timeout: TimeSpan.FromSeconds(1)
));
```
#### `Cd(string)`
```csharp
Cd("/usr/local/bin"); // equivalent to `Environment.CurrentDirectory = "/usr/local/bin";`
```
Dispose the return value of `Cd` method to return to the previous directory.
```csharp
Cd("/"); // The current directory is "/".
using (Cd("/usr/local/bin"))
{
// The current directory is "/usr/local/bin".
}
// The current directory is "/" again.
```
#### `Mkdirp(string path)`
Same as `mkdir -p`. Creates a new directory and any necessary sub-directories in the specified path.
#### `Dump(T value)`
Formats the object and write it to the console.
```csharp
Dump(new { Foo = 123, Bar = "Baz" }); // => "{ Foo = 123, Bar = "Baz" }"
```
#### `Which(string name)`, `TryWhich(string name, out string path)`
Returns a path of the specified command.
```csharp
var dotnetPath = Which("dotnet");
await Run($"{dotnetPath} run");
```
#### `Echo(object message = default)`
`Echo` method is equivalent to Console.WriteLine.
```csharp
Echo("Hello World!"); // equivalent to Console.WriteLine("Hello World!");
```
#### `Sleep(int duration)`, `Sleep(TimeSpan duration)`
Returns a Task that waits for the specified duration.
```csharp
await Sleep(10); // Sleep for 10 seconds.
```
#### `Exit(int exitCode)`
Terminates the application with an exit code.
```csharp
Exit(1);
```
### Properties
#### `Env.Vars`
Exposes the environment variables as `IDictionary`.
```csharp
Env.Vars["PATH"] = Env.Vars["PATH"] + ":/path/to/";
```
#### `Env.IsWindows`
Returns whether the running operating system is Windows or not. If it returns `false`, the operating system is Linux or macOS.
```csharp
if (Env.IsWindows) { /* Something to do for Windows */ }
```
#### `Env.Shell`
Specify explicitly which shell to use, or set to not use a shell.
```csharp
Env.Shell.UseBash();
Env.Shell.NoUseShell();
Env.Shell.UseCmd();
```
#### `Env.Verbosity`
Sets or gets the output level when executing a command/process.
- `Verbosity.All`: Displays both the command line and the output of the command
- `Verbosity.CommandLine`: Displays the command line
- `Verbosity.Output`: Displays the output of the command
- `Verbosity.Silent`: No display
#### `Env.ProcessTimeout`
Sets the timeout for running the process. The default value is `0` (disabled).
```csharp
Env.ProcessTimeout = TimeSpan.FromSecond(1);
// OperationCanceledException will be thrown after 1s.
await Run($"ping -t localhost");
```
#### `Arguments`
Gets the arguments passed to the current application.
```csharp
// $ myapp foo bar baz => new [] { "foo", "bar", "baz" };
foreach (var arg in Arguments) { /* ... */ }
```
#### `CurrentDirectory`, `ExecutableDirectory`, `ExecutableName`, `ExecutablePath`
Gets the current directory and the application directory or name or path.
```csharp
// C:\> cd C:\Users\Alice
// C:\Users\Alice> Downloads\MyApp.exe
Echo(CurrentDirectory); // C:\Users\Alice
Echo(ExecutableDirectory); // C:\Users\Alice\Downloads
Echo(ExecutableName); // MyApp.exe
Echo(ExecutablePath); // C:\Users\Alice\Downloads\MyApp.exe
```
#### `HomeDirectory`
Gets the path of the current user's home directory.
```csharp
// Windows: C:/Users/
// Linux: /home/
// macOS: /Users/
Echo(HomeDirectory);
```
#### `StdIn`, `StdOut`, `StdErr`
Provides the wrapper with methods useful for reading and writing to the standard input/output/error streams.
```csharp
// Reads data from standard input.
await StdIn.ReadToEndAsync();
// Writes data to standard output or error.
StdOut.WriteLine("FooBar");
StdErr.WriteLine("Oops!");
```
## ProcessTask class
Represents the execution task of the process started by `Run`.
### `Pipe`
Connects the standard output of the process to another `ProcessTask` or `Stream`.
```csharp
await (Run($"ls -lF") | Run($"grep .dll"));
// The followings are equivalent to using '|'.
var procTask1 = Run($"ls -lF");
var procTask2 = Run($"grep .dll");
procTask1.Pipe(procTask2);
```
A `Stream` can also be passed to Pipe. If the ProcessTask has connected to the `Stream`, it will not write to `ProcessOutput`.
```csharp
var memStream = new MemoryStream();
await Run($"ls -lF").Pipe(memStream);
```
### `ConnectStreamToStandardInput`
Connects the Stream to the standard input of the process. The method can be called only once before the process starts.
```csharp
await (myStream | Run($"grep .dll"));
// The followings are equivalent to using '|'.
var procTask = Run($"grep .dll");
procTask.ConnectStreamToStandardInput(myStream);
```
### `NoThrow`
Suppresses exception throwing when the exit code is non-zero.
```csharp
await Run($"AppReturnsExitCodeNonZero").NoThrow();
```
### `SuppressConsoleOutputs`
Suppresses the writing of command execution results to the standard output.
```csharp
// equivalent to "Env.Verbosity = Verbosity.Silent" or pipe to null.
await Run($"ls -lF").SuppressConsoleOutputs();
```
### `ExitCode`
Returns a `Task` to get the exit code of the process. This is equivalent to waiting for a `ProcessTask` with `NoThrow`.
```csharp
var proc = Run($"ls -lF");
if (await proc.ExitCode != 0)
{
...
}
// equivalent to `(await Run($"ls -lF").NoThrow()).ExitCode`
```
## ProcessOutput class
Provides the results of the process execution.
### `Combined`, `CombinedBinary`
Gets the combined standard output and error as a string or byte array.
### `Output`, `OutputBinary`
Gets the standard output as a string or byte array.
### `Error`, `ErrorBinary`
Gets the standard error as a string or byte array.
### `AsLines(bool trimEnd = false)`, `GetEnumerator()`
Gets the combined standard output and error as a per-line `IEnumerable`.
```csharp
// equivalent to `foreach (var line in procOutput.AsLines())`
foreach (var line in procOutput) { ... }
```
### `ToString()`
The method equivalent to `Combined` property.
### `ExitCode`
Gets the exit code of the process.
## Utilities and shortcuts
Chell.Exports class also exposes a variety of useful utilities and shortcuts to libraries.
### `Prompt`
Prompts the user for input and gets it.
```csharp
var name = await Prompt("What's your name? ");
```
### `Chalk`: Kokuban: Terminal string styling
Provides a shortcut to [mayuki/Kokuban](https://github.com/mayuki/Kokuban). You can easily style the text on the terminal.
```csharp
// "Error: " will be colored.
Echo((Chalk.Red + "Error: ") + "Something went wrong.");
```
### `Glob`
Provides a shortcut to `Microsoft.Extensions.FileSystemGlobbing`.
- `Glob(params string[] patterns)`
- `Glob(string baseDir, string[] patterns)`
```csharp
// Glob patterns starting with '!' will be treated as excludes.
foreach (var path in Glob("**/*.cs", "!**/*.vb"))
{
...
}
```
### JSON serialize/deserialize (System.Text.Json)
Provides shortcuts to `System.Text.Json`.
- `ToJson(T obj)`
```csharp
var obj = new { Name = "Alice", Age = 18 };
var json = ToJson(obj);
Echo(json); // {"Name":"Alice","Age":18}
```
- `FromJson(string json)`
- `FromJson(string json, T shape)`
```csharp
var json = "{ \"foo\": 123 }";
var obj = FromJson(json, new { Foo = 0 });
Dump(obj); // { Foo = 123 }
```
- `AsJson`
- `AsJsonLines`
```csharp
using Chell;
var output = await Run($"docker image ls --format {"{{json .}}"}");
foreach (var image in output.AsJsonLines(new { Repository = "", ID = "", Tag = ""}))
{
// ...
}
```
```csharp
using Chell;
var output = await Run($"kubectl version --client -o json");
var obj = output.AsJson(new { clientVersion = new { major = "", minor = "", gitVersion = "" } });
Echo(obj); // { clientVersion = { major = 1, minor = 21, gitVersion = v1.21.2 } }
```
### HTTP acccess (System.Net.Http)
Provides shortcuts to `System.Net.Http.HttpClient`.
- `FetchAsync`
- `FetchByteArrayAsync`
- `FetchStreamAsync`
- `FetchStringAsync`
## Chell as a Library
Chell can also be used as a utility library to run processes.
If you don't use `Chell.Exports`, you won't get any unnecessary methods or properties, and you can use `Run` and `ChellEnvironment`, `Exports` class.
```csharp
using Chell;
var results = await new Run($"ls -lF");
// ChellEnvironment.Current is equivalent to `Env` on `Chell.Exports`.
Console.WriteLine(ChellEnvironment.Current.ExecutablePath);
Console.WriteLine(ChellEnvironment.Current.ExecutableName);
Console.WriteLine(ChellEnvironment.Current.Arguments);
Console.WriteLine(ChellEnvironment.Current.Vars["PATH"]);
```
## Chell.Run
Chell.Run executes the input source code in an environment where Chell and some libraries are available.
It does not perform any NuGet package resolution, so we recommend creating a typical C# project if you need to handle such complexities.
```
$ dotnet tool install -g Chell.Run
```
```bash
$ chell -e "Echo(123);"
$ chell <
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
================================================
FILE: samples/GettingStarted.Basic.Unix/GettingStarted.Basic.Unix.csproj
================================================
Exe
net5.0
false
================================================
FILE: samples/GettingStarted.Basic.Unix/Program.cs
================================================
using System;
using System.Linq;
using static Chell.Exports;
// Starts a process.
// The array will be expanded and the elements will be escaped
var dirs = new[] { "/", "/usr", "/bin" };
var results = await Run($"ls -l {dirs}");
// Enumerates the results to retrieve the standard output line by line.
foreach (var line in results)
{
Echo($"Result> {line}");
}
Echo();
// Built-in Variables
Echo((Chalk.Green + "ExecutableName: ") + string.Join(' ', ExecutableName));
Echo((Chalk.Green + "ExecutableDirectory: ") + string.Join(' ', ExecutableDirectory));
Echo((Chalk.Green + "Arguments: ") + string.Join(' ', Arguments));
Echo((Chalk.Green + "CurrentDirectory: ") + string.Join(' ', CurrentDirectory));
Echo();
// Environment Variables
Echo((Chalk.Green + "Env.Vars[\"PATH\"]: ") + Env.Vars["PATH"]);
Echo();
// Standard Input/Error as Stream + Utility methods.
StdOut.WriteLine("Hello World!");
StdErr.WriteLine("Hello World! (Error)");
Echo();
// Get the data from network and pipe it to the process
await (await FetchByteArrayAsync("http://www.example.com/") | Run("grep title"));
// Temporarily change the current directory.
using (Cd("/"))
{
await Run($"dir");
}
Exit(1);
================================================
FILE: samples/GettingStarted.Basic.Windows/GettingStarted.Basic.Windows.csproj
================================================
Exe
net5.0
false
================================================
FILE: samples/GettingStarted.Basic.Windows/Program.cs
================================================
using System;
using System.Linq;
using Chell;
using static Chell.Exports;
// Starts a process.
// The array will be expanded and the elements will be escaped
var dirs = new[] { @"C:\Windows\Microsoft.NET", @"C:\Program Files" };
var results = await Run($"dir {dirs}"); //
// Enumerates the results to retrieve the standard output line by line.
foreach (var line in results.Where(x => x.Contains("Windows")))
{
Echo($"Result> {line}");
}
Echo();
// Built-in Variables
Echo((Chalk.Green + "ExecutableName: ") + string.Join(' ', ExecutableName));
Echo((Chalk.Green + "ExecutableDirectory: ") + string.Join(' ', ExecutableDirectory));
Echo((Chalk.Green + "Arguments: ") + string.Join(' ', Arguments));
Echo((Chalk.Green + "CurrentDirectory: ") + string.Join(' ', CurrentDirectory));
Echo();
// Environment Variables
Echo((Chalk.Green + "Env.Vars[\"PATH\"]: ") + Env.Vars["PATH"]);
Echo();
// Standard Input/Error as Stream + Utility methods.
StdOut.WriteLine("Hello World!");
StdErr.WriteLine("Hello World! (Error)");
Echo();
// Get the data from network and pipe it to the process
await (await FetchByteArrayAsync("http://www.example.com/") | Run("findstr title"));
// Temporarily change the current directory.
using (Cd("C:\\Users"))
{
await Run($"dir");
}
Exit(1);
================================================
FILE: src/.editorconfig
================================================
###############################
# C# Nullability #
###############################
[*.cs]
# CS8618: Non-nullable field is uninitialized. Consider declaring as nullable.
dotnet_diagnostic.CS8618.severity = error
# CS8604: Possible null reference argument.
dotnet_diagnostic.CS8604.severity = error
# CS8629: Nullable value type may be null.
dotnet_diagnostic.CS8629.severity = error
# CS8600: Converting null literal or possible null value to non-nullable type.
dotnet_diagnostic.CS8600.severity = error
# CS8603: Possible null reference return.
dotnet_diagnostic.CS8603.severity = error
# CS8610: Nullability of reference types in type of parameter doesn't match overridden member.
dotnet_diagnostic.CS8610.severity = error
# CS8625: Cannot convert null literal to non-nullable reference type.
dotnet_diagnostic.CS8625.severity = error
# CS8606: Possible null reference assignment to iteration variable
dotnet_diagnostic.CS8606.severity = error
# CS8602: Dereference of a possibly null reference.
dotnet_diagnostic.CS8602.severity = error
# CS8601: Possible null reference assignment.
dotnet_diagnostic.CS8601.severity = error
# CS8614: Nullability of reference types in type of parameter doesn't match implicitly implemented member.
dotnet_diagnostic.CS8614.severity = error
================================================
FILE: src/Chell/Chell.csproj
================================================
netstandard2.1;netcoreapp3.1;net5.0
latest
enable
true
TextTemplatingFileGenerator
ProcessTaskExtensions.Generated.cs
TextTemplatingFileGenerator
ChellWritableStream.Generated.cs
True
True
ProcessTaskExtensions.tt
True
True
ChellWritableStream.tt
================================================
FILE: src/Chell/ChellEnvironment.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Chell.Internal;
using Chell.IO;
using Chell.Shell;
namespace Chell
{
[Flags]
public enum ChellVerbosity
{
///
/// By default, no output is written to the console.
///
Silent = 0,
///
/// Writes a executing command line to the console.
///
CommandLine = 1 << 0,
///
/// Writes a command output to the console.
///
ConsoleOutputs = 1 << 1,
///
/// Writes all command lines and command outputs.
///
Full = CommandLine | ConsoleOutputs,
[EditorBrowsable(EditorBrowsableState.Never)]
Debug = Full | 1 << 31,
}
public class ChellEnvironment
{
public static ChellEnvironment Current { get; set; } = new ChellEnvironment();
private string[] _arguments;
private string? _executablePath;
private string _executableName;
private string _executableDirectory;
public ChellEnvironment()
{
var args = Environment.GetCommandLineArgs();
var path = args[0];
_arguments = args.Skip(1).ToArray();
_executablePath = path;
_executableName = Path.GetFileName(path);
_executableDirectory = Path.GetDirectoryName(path)!;
}
///
/// Gets or sets the verbosity.
///
public ChellVerbosity Verbosity { get; set; } = ChellVerbosity.Full;
public ShellExecutorProvider Shell { get; } = new ShellExecutorProvider();
public IConsoleProvider Console { get; set; } =
LINQPadHelper.RunningOnLINQPad
? new LINQPadConsoleProvider()
: SystemConsoleProvider.Instance;
///
/// Gets the identifier for the current application process.
///
public int ProcessId =>
#if NET5_0_OR_GREATER
Environment.ProcessId
#else
Process.GetCurrentProcess().Id
#endif
;
///
/// Gets whether the current application is running on Windows.
///
public bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
///
/// Gets the command line arguments. like args of a entry point.
///
public IReadOnlyList Arguments => _arguments;
///
/// Gets the path of the executing application. like argv[0]. (e.g. C:\\Path\To\App.exe, /path/to/app)
///
///
/// The path may be null when running a inline script.
///
public string? ExecutablePath => _executablePath;
///
/// Gets the name of the executing application. like argv[0]. (e.g. App.exe, app)
///
public string ExecutableName => _executableName;
///
/// Gets the directory of the executing application. like argv[0]. (e.g. C:\\Path\To, /path/to)
///
public string ExecutableDirectory => _executableDirectory;
///
/// Gets or sets the path of the current working directory.
///
public string CurrentDirectory
{
get => Environment.CurrentDirectory;
set => Environment.CurrentDirectory = value;
}
///
/// Gets the path of the current user's home directory.
///
public string HomeDirectory => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
///
/// Gets the environment variables as representation.
///
public IDictionary Vars { get; } = new EnvironmentVariables();
///
/// Gets the standard input stream.
///
public ChellReadableStream StdIn => new ChellReadableStream(this.Console.OpenStandardInput(), this.Console.InputEncoding);
///
/// Gets the standard output stream.
///
public ChellWritableStream StdOut => new ChellWritableStream(this.Console.OpenStandardOutput(), this.Console.OutputEncoding);
///
/// Gets the standard output stream.
///
public ChellWritableStream StdErr => new ChellWritableStream(this.Console.OpenStandardError(), this.Console.OutputEncoding);
///
/// Gets or sets the default timeout for the process. The value affects the current application. The default value is .
///
///
/// If the value is or , the process will not be timed out.
///
public TimeSpan ProcessTimeout { get; set; } = TimeSpan.Zero;
[EditorBrowsable(EditorBrowsableState.Never)]
public void SetCommandLineArgs(string? executablePath, string executableName, string executableDirectory, string[] args)
{
_arguments = args.ToArray();
_executableName = executableName;
_executablePath = executablePath;
_executableDirectory = executableDirectory;
}
}
}
================================================
FILE: src/Chell/CommandLineString.cs
================================================
using System;
using System.ComponentModel;
using System.Diagnostics;
namespace Chell
{
///
/// Workaround for string/FormattableString overload issues
///
[EditorBrowsable(EditorBrowsableState.Never)]
[DebuggerDisplay("CommandLineString: String={StringValue,nq}; FormattableString={FormattableStringValue,nq}")]
public readonly struct CommandLineString
{
public string? StringValue { get; }
public FormattableString? FormattableStringValue { get; }
public CommandLineString(string value)
{
StringValue = value;
FormattableStringValue = null;
}
public CommandLineString(FormattableString value)
{
StringValue = null;
FormattableStringValue = value;
}
public static implicit operator CommandLineString(string value)
{
return new CommandLineString(value);
}
public static implicit operator CommandLineString(FormattableString value)
{
return new CommandLineString(value);
}
}
}
================================================
FILE: src/Chell/Exports.cs
================================================
using Microsoft.Extensions.FileSystemGlobbing;
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Chell.Internal;
using Chell.IO;
using Kokuban;
using Kokuban.AnsiEscape;
namespace Chell
{
public static class Exports
{
public static class Verbosity
{
///
/// By default, no output is written to the console.
///
public const ChellVerbosity Silent = ChellVerbosity.Silent;
///
/// Writes a executing command line to the console.
///
public const ChellVerbosity CommandLine = ChellVerbosity.CommandLine;
///
/// Writes a command output to the console.
///
public const ChellVerbosity ConsoleOutputs = ChellVerbosity.ConsoleOutputs;
///
/// Writes all command lines and command outputs.
///
public const ChellVerbosity Full = ChellVerbosity.Full;
}
///
/// Gets the current environment.
///
public static ChellEnvironment Env => ChellEnvironment.Current;
///
/// Gets the standard input stream.
///
public static ChellReadableStream StdIn => Env.StdIn;
///
/// Gets the standard output stream.
///
public static ChellWritableStream StdOut => Env.StdOut;
///
/// Gets the standard error stream.
///
public static ChellWritableStream StdErr => Env.StdErr;
///
/// Gets the command line arguments. like args of a entry point.
///
public static IReadOnlyList Arguments => Env.Arguments;
///
/// Gets the path of the executing application. like argv[0]. (e.g. C:\\Path\To\App.exe, /path/to/app)
///
///
/// The path may be null when running a inline script.
///
public static string? ExecutablePath => Env.ExecutablePath;
///
/// Gets the name of the executing application. like argv[0]. (e.g. App.exe, app)
///
public static string ExecutableName => Env.ExecutableName;
///
/// Gets the directory of the executing application. like argv[0]. (e.g. C:\\Path\To, /path/to)
///
public static string ExecutableDirectory => Env.ExecutableDirectory;
///
/// Gets or sets the path of the current working directory.
///
public static string CurrentDirectory
{
get => Env.CurrentDirectory;
set => Env.CurrentDirectory = value;
}
///
/// Gets the identifier for the current application process.
///
public static int ProcessId => Env.ProcessId;
///
/// Gets the Kokuban ANSI style builder to decorate texts.
///
public static AnsiStyle Chalk => Kokuban.Chalk.Create(KokubanOptions.Default);
///
/// Starts the process task with the specified command line.
///
///
///
///
public static ProcessTask Run(FormattableString commandLine, ProcessTaskOptions? options = default)
=> new ProcessTask(commandLine, options);
///
/// Starts the process task with the specified command line.
///
///
///
///
public static ProcessTask Run(CommandLineString commandLine, ProcessTaskOptions? options = default)
=> new ProcessTask(commandLine, options);
///
/// Starts the process task with the specified command line.
///
/// The data to be passed to the standard input of the process.
///
///
///
public static ProcessTask Run(Stream inputStream, FormattableString commandLine, ProcessTaskOptions? options = default)
=> new ProcessTask(inputStream, commandLine, options);
///
/// Starts the process task with the specified command line.
///
/// The data to be passed to the standard input of the process.
///
///
///
public static ProcessTask Run(Stream inputStream, CommandLineString commandLine, ProcessTaskOptions? options = default)
=> new ProcessTask(inputStream, commandLine, options);
///
/// Starts the process task with the specified command line.
///
/// The data to be passed to the standard input of the process.
///
///
///
public static ProcessTask Run(ReadOnlyMemory inputData, FormattableString commandLine, ProcessTaskOptions? options = default)
=> new ProcessTask(inputData, commandLine, options);
///
/// Starts the process task with the specified command line.
///
/// The data to be passed to the standard input of the process.
///
///
///
public static ProcessTask Run(ReadOnlyMemory inputData, CommandLineString commandLine, ProcessTaskOptions? options = default)
=> new ProcessTask(inputData, commandLine, options);
///
/// Writes the message to the console.
///
///
public static void Echo(object? message = default)
=> ChellEnvironment.Current.Console.Out.WriteLine(message);
///
/// Writes the object details to the console.
///
///
///
public static void Dump(T obj)
=> ObjectDumper.Dump(obj);
///
/// Converts the object to a JSON.
///
///
public static string ToJson(T obj, JsonSerializerOptions? options = default)
=> JsonSerializer.Serialize(obj, options);
///
/// Converts the JSON to an object.
///
///
public static T? FromJson(string json, T shape)
=> FromJson(json);
///
/// Converts the JSON to an object.
///
///
public static T? FromJson(string json)
=> Chell.Extensions.StringExtensions.AsJson(json);
///
/// Changes the current directory to the specified path.
///
///
/// Dispose the return value to return to the previous directory.
///
///
public static IDisposable Cd(string path)
=> new ChangeDirectoryScope(path);
private class ChangeDirectoryScope : IDisposable
{
private readonly string _previousCurrentDirectory;
public ChangeDirectoryScope(string newCurrentDirectory)
{
_previousCurrentDirectory = Environment.CurrentDirectory;
ChangeDirectory(newCurrentDirectory);
}
public void Dispose()
{
ChangeDirectory(_previousCurrentDirectory);
}
private void ChangeDirectory(string path)
{
CommandLineHelper.WriteCommandLineToConsole(ChellEnvironment.Current.Console, $"cd {path}");
Environment.CurrentDirectory = path;
}
}
///
/// Sleeps for the specified time.
///
///
///
public static Task Sleep(TimeSpan timeSpan)
=> Task.Delay(timeSpan);
///
/// Sleeps for the specified time.
///
///
///
public static Task Sleep(int seconds)
=> Task.Delay(TimeSpan.FromSeconds(seconds));
///
/// Get the task to ignore the exception and return .
///
///
///
public static Task NoThrow(ProcessTask task)
=> task.NoThrow();
///
/// Terminates the current process with specified exit code.
///
///
public static void Exit(int exitCode = 0)
=> Environment.Exit(exitCode);
///
/// Creates a new directory and any necessary sub-directories in the specified path.
///
///
public static void Mkdirp(string path)
=> Directory.CreateDirectory(path);
///
/// Fetches the content of the specified URL using GET method.
///
///
///
///
public static Task FetchAsync(string requestUri, CancellationToken cancellationToken = default)
{
CommandLineHelper.WriteCommandLineToConsole(ChellEnvironment.Current.Console, $"{nameof(FetchAsync)} {requestUri}");
var httpClient = new HttpClient();
return httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, requestUri), cancellationToken);
}
///
/// Fetches the content of the specified URL as string using GET method.
///
///
///
///
public static async Task FetchStringAsync(string requestUri, CancellationToken cancellationToken = default)
{
CommandLineHelper.WriteCommandLineToConsole(ChellEnvironment.Current.Console, $"{nameof(FetchStringAsync)} {requestUri}");
var httpClient = new HttpClient();
var res = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, requestUri), cancellationToken);
res.EnsureSuccessStatusCode();
#if NET5_0_OR_GREATER
return await res.Content.ReadAsStringAsync(cancellationToken);
#else
return await res.Content.ReadAsStringAsync();
#endif
}
///
/// Fetches the content of the specified URL as byte[] using GET method.
///
///
///
///
public static async Task FetchByteArrayAsync(string requestUri, CancellationToken cancellationToken = default)
{
CommandLineHelper.WriteCommandLineToConsole(ChellEnvironment.Current.Console, $"{nameof(FetchByteArrayAsync)} {requestUri}");
var httpClient = new HttpClient();
var res = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, requestUri), cancellationToken);
res.EnsureSuccessStatusCode();
#if NET5_0_OR_GREATER
return await res.Content.ReadAsByteArrayAsync(cancellationToken);
#else
return await res.Content.ReadAsByteArrayAsync();
#endif
}
///
/// Fetches the content of the specified URL as Stream using GET method.
///
///
///
///
public static async Task FetchStreamAsync(string requestUri, CancellationToken cancellationToken = default)
{
CommandLineHelper.WriteCommandLineToConsole(ChellEnvironment.Current.Console, $"{nameof(FetchStreamAsync)} {requestUri}");
var httpClient = new HttpClient();
var res = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, requestUri), cancellationToken);
res.EnsureSuccessStatusCode();
#if NET5_0_OR_GREATER
return await res.Content.ReadAsStreamAsync(cancellationToken);
#else
return await res.Content.ReadAsStreamAsync();
#endif
}
///
/// Gets the full path to a command, similar to the `which` command on Unix.
///
///
///
public static string Which(string commandName)
=> Internal.Which.TryGetPath(commandName, out var matchedPath)
? matchedPath
: throw new FileNotFoundException($"Command '{commandName}' is not found.");
///
/// Gets the full path to a command, similar to the `which` command on Unix.
///
///
///
///
public static bool TryWhich(string commandName, out string matchedPath)
=> Internal.Which.TryGetPath(commandName, out matchedPath);
///
/// Enumerates paths under the current directory that match the specified glob pattern.
///
///
/// A glob pattern accepts * and ** (e.g. **/*.cs). If the specify a pattern is started with '!', it will be treated as an excluded pattern.
///
///
///
public static IEnumerable Glob(params string[] patterns)
=> Glob(Environment.CurrentDirectory, patterns);
///
/// Enumerates paths under the specified directory that match the specified glob pattern.
///
///
/// A glob pattern accepts * and ** (e.g. **/*.cs). If the specify a pattern is started with '!', it will be treated as an excluded pattern.
///
///
///
///
public static IEnumerable Glob(string baseDir, string[] patterns)
{
var matcher = new Matcher();
foreach (var pattern in patterns)
{
if (pattern.StartsWith("!"))
{
matcher.AddExclude(pattern.Substring(1));
}
else
{
matcher.AddInclude(pattern);
}
}
var result = matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(baseDir)));
return result.Files
.Select(x => Path.GetFullPath(Path.Combine(baseDir, x.Stem))); // NOTE: Microsoft.Extensions.FileSystemGlobbing 5.0.0 does not reflect the root directory in `Path`.
}
///
/// Displays the message and reads lines entered by the user from the console.
///
///
///
public static async Task Prompt(string message)
{
Console.Write(message);
return await Console.In.ReadLineAsync();
}
}
}
================================================
FILE: src/Chell/Extensions/ChellExtensions.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Chell.Internal;
namespace Chell.Extensions
{
public static class ChellExtensions
{
///
/// Writes a object details to the output.
///
///
///
///
public static T Dump(this T value)
{
return ObjectDumper.Dump(value);
}
///
/// Writes a object details to the output.
///
///
///
///
public static async Task Dump(this Task task)
{
var result = await task.ConfigureAwait(false);
ObjectDumper.Dump(result);
return result;
}
}
}
================================================
FILE: src/Chell/Extensions/ProcessOutputExtensions.cs
================================================
using System.Collections.Generic;
using System.Text.Json;
namespace Chell
{
public static class ProcessOutputExtensions
{
///
/// Enumerates lines by converting them to objects as JSON.
///
///
/// Converts to the anonymous type specified in argument.
///
public static IEnumerable AsJsonLines(this ProcessOutput processOutput, T shape, bool skipEmptyLine = true, JsonSerializerOptions? options = null)
=> Chell.Extensions.StringExtensions.AsJsonLines(processOutput.AsLines(), skipEmptyLine, options);
///
/// Enumerates lines by converting them to objects as JSON.
///
public static IEnumerable AsJsonLines(this ProcessOutput processOutput, bool skipEmptyLine = true, JsonSerializerOptions? options = null)
=> Chell.Extensions.StringExtensions.AsJsonLines(processOutput.AsLines(), skipEmptyLine, options);
///
/// Converts the output string to an object as JSON.
///
///
/// Converts to the anonymous type specified in argument.
///
public static T? AsJson(this ProcessOutput processOutput, T shape, JsonSerializerOptions? options = null)
=> AsJson(processOutput, options);
///
/// Converts the output string to an object as JSON.
///
public static T? AsJson(this ProcessOutput processOutput, JsonSerializerOptions? options = null)
=> JsonSerializer.Deserialize(processOutput.ToString(), options);
}
}
================================================
FILE: src/Chell/Extensions/ProcessTaskExtensions.Generated.cs
================================================
///
using System.Threading.Tasks;
namespace Chell
{
public static partial class ProcessTaskExtensions
{
public static System.Runtime.CompilerServices.TaskAwaiter<(ProcessOutput Result1, ProcessOutput Result2)> GetAwaiter(this (ProcessTask T1, ProcessTask T2) tasks)
{
static async Task<(ProcessOutput Result1, ProcessOutput Result2)> WhenAllAsync(ProcessTask t1, ProcessTask t2)
{
var results = await Task.WhenAll(t1, t2).ConfigureAwait(false);
return (results[0], results[1]);
}
return WhenAllAsync(tasks.T1, tasks.T2).GetAwaiter();
}
public static System.Runtime.CompilerServices.TaskAwaiter<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3)> GetAwaiter(this (ProcessTask T1, ProcessTask T2, ProcessTask T3) tasks)
{
static async Task<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3)> WhenAllAsync(ProcessTask t1, ProcessTask t2, ProcessTask t3)
{
var results = await Task.WhenAll(t1, t2, t3).ConfigureAwait(false);
return (results[0], results[1], results[2]);
}
return WhenAllAsync(tasks.T1, tasks.T2, tasks.T3).GetAwaiter();
}
public static System.Runtime.CompilerServices.TaskAwaiter<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4)> GetAwaiter(this (ProcessTask T1, ProcessTask T2, ProcessTask T3, ProcessTask T4) tasks)
{
static async Task<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4)> WhenAllAsync(ProcessTask t1, ProcessTask t2, ProcessTask t3, ProcessTask t4)
{
var results = await Task.WhenAll(t1, t2, t3, t4).ConfigureAwait(false);
return (results[0], results[1], results[2], results[3]);
}
return WhenAllAsync(tasks.T1, tasks.T2, tasks.T3, tasks.T4).GetAwaiter();
}
public static System.Runtime.CompilerServices.TaskAwaiter<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5)> GetAwaiter(this (ProcessTask T1, ProcessTask T2, ProcessTask T3, ProcessTask T4, ProcessTask T5) tasks)
{
static async Task<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5)> WhenAllAsync(ProcessTask t1, ProcessTask t2, ProcessTask t3, ProcessTask t4, ProcessTask t5)
{
var results = await Task.WhenAll(t1, t2, t3, t4, t5).ConfigureAwait(false);
return (results[0], results[1], results[2], results[3], results[4]);
}
return WhenAllAsync(tasks.T1, tasks.T2, tasks.T3, tasks.T4, tasks.T5).GetAwaiter();
}
public static System.Runtime.CompilerServices.TaskAwaiter<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5, ProcessOutput Result6)> GetAwaiter(this (ProcessTask T1, ProcessTask T2, ProcessTask T3, ProcessTask T4, ProcessTask T5, ProcessTask T6) tasks)
{
static async Task<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5, ProcessOutput Result6)> WhenAllAsync(ProcessTask t1, ProcessTask t2, ProcessTask t3, ProcessTask t4, ProcessTask t5, ProcessTask t6)
{
var results = await Task.WhenAll(t1, t2, t3, t4, t5, t6).ConfigureAwait(false);
return (results[0], results[1], results[2], results[3], results[4], results[5]);
}
return WhenAllAsync(tasks.T1, tasks.T2, tasks.T3, tasks.T4, tasks.T5, tasks.T6).GetAwaiter();
}
public static System.Runtime.CompilerServices.TaskAwaiter<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5, ProcessOutput Result6, ProcessOutput Result7)> GetAwaiter(this (ProcessTask T1, ProcessTask T2, ProcessTask T3, ProcessTask T4, ProcessTask T5, ProcessTask T6, ProcessTask T7) tasks)
{
static async Task<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5, ProcessOutput Result6, ProcessOutput Result7)> WhenAllAsync(ProcessTask t1, ProcessTask t2, ProcessTask t3, ProcessTask t4, ProcessTask t5, ProcessTask t6, ProcessTask t7)
{
var results = await Task.WhenAll(t1, t2, t3, t4, t5, t6, t7).ConfigureAwait(false);
return (results[0], results[1], results[2], results[3], results[4], results[5], results[6]);
}
return WhenAllAsync(tasks.T1, tasks.T2, tasks.T3, tasks.T4, tasks.T5, tasks.T6, tasks.T7).GetAwaiter();
}
public static System.Runtime.CompilerServices.TaskAwaiter<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5, ProcessOutput Result6, ProcessOutput Result7, ProcessOutput Result8)> GetAwaiter(this (ProcessTask T1, ProcessTask T2, ProcessTask T3, ProcessTask T4, ProcessTask T5, ProcessTask T6, ProcessTask T7, ProcessTask T8) tasks)
{
static async Task<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5, ProcessOutput Result6, ProcessOutput Result7, ProcessOutput Result8)> WhenAllAsync(ProcessTask t1, ProcessTask t2, ProcessTask t3, ProcessTask t4, ProcessTask t5, ProcessTask t6, ProcessTask t7, ProcessTask t8)
{
var results = await Task.WhenAll(t1, t2, t3, t4, t5, t6, t7, t8).ConfigureAwait(false);
return (results[0], results[1], results[2], results[3], results[4], results[5], results[6], results[7]);
}
return WhenAllAsync(tasks.T1, tasks.T2, tasks.T3, tasks.T4, tasks.T5, tasks.T6, tasks.T7, tasks.T8).GetAwaiter();
}
public static System.Runtime.CompilerServices.TaskAwaiter<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5, ProcessOutput Result6, ProcessOutput Result7, ProcessOutput Result8, ProcessOutput Result9)> GetAwaiter(this (ProcessTask T1, ProcessTask T2, ProcessTask T3, ProcessTask T4, ProcessTask T5, ProcessTask T6, ProcessTask T7, ProcessTask T8, ProcessTask T9) tasks)
{
static async Task<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5, ProcessOutput Result6, ProcessOutput Result7, ProcessOutput Result8, ProcessOutput Result9)> WhenAllAsync(ProcessTask t1, ProcessTask t2, ProcessTask t3, ProcessTask t4, ProcessTask t5, ProcessTask t6, ProcessTask t7, ProcessTask t8, ProcessTask t9)
{
var results = await Task.WhenAll(t1, t2, t3, t4, t5, t6, t7, t8, t9).ConfigureAwait(false);
return (results[0], results[1], results[2], results[3], results[4], results[5], results[6], results[7], results[8]);
}
return WhenAllAsync(tasks.T1, tasks.T2, tasks.T3, tasks.T4, tasks.T5, tasks.T6, tasks.T7, tasks.T8, tasks.T9).GetAwaiter();
}
public static System.Runtime.CompilerServices.TaskAwaiter<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5, ProcessOutput Result6, ProcessOutput Result7, ProcessOutput Result8, ProcessOutput Result9, ProcessOutput Result10)> GetAwaiter(this (ProcessTask T1, ProcessTask T2, ProcessTask T3, ProcessTask T4, ProcessTask T5, ProcessTask T6, ProcessTask T7, ProcessTask T8, ProcessTask T9, ProcessTask T10) tasks)
{
static async Task<(ProcessOutput Result1, ProcessOutput Result2, ProcessOutput Result3, ProcessOutput Result4, ProcessOutput Result5, ProcessOutput Result6, ProcessOutput Result7, ProcessOutput Result8, ProcessOutput Result9, ProcessOutput Result10)> WhenAllAsync(ProcessTask t1, ProcessTask t2, ProcessTask t3, ProcessTask t4, ProcessTask t5, ProcessTask t6, ProcessTask t7, ProcessTask t8, ProcessTask t9, ProcessTask t10)
{
var results = await Task.WhenAll(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10).ConfigureAwait(false);
return (results[0], results[1], results[2], results[3], results[4], results[5], results[6], results[7], results[8], results[9]);
}
return WhenAllAsync(tasks.T1, tasks.T2, tasks.T3, tasks.T4, tasks.T5, tasks.T6, tasks.T7, tasks.T8, tasks.T9, tasks.T10).GetAwaiter();
}
}
}
================================================
FILE: src/Chell/Extensions/ProcessTaskExtensions.cs
================================================
using System.Threading.Tasks;
namespace Chell
{
public static partial class ProcessTaskExtensions
{
}
}
================================================
FILE: src/Chell/Extensions/ProcessTaskExtensions.tt
================================================
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".Generated.cs" #>
///
using System.Threading.Tasks;
namespace Chell
{
public static partial class ProcessTaskExtensions
{
<# for (var i = 2; i <= 10; i++) {
var inTuple = string.Join(", ", Enumerable.Range(1, i).Select(x => $"ProcessTask T{x}"));
var outTuple = string.Join(", ", Enumerable.Range(1, i).Select(x => $"ProcessOutput Result{x}"));
#>
public static System.Runtime.CompilerServices.TaskAwaiter<(<#= outTuple #>)> GetAwaiter(this (<#= inTuple #>) tasks)
{
static async Task<(<#= outTuple #>)> WhenAllAsync(<#= string.Join(", ", Enumerable.Range(1, i).Select(x => $"ProcessTask t{x}")) #>)
{
var results = await Task.WhenAll(<#= string.Join(", ", Enumerable.Range(1, i).Select(x => $"t{x}")) #>).ConfigureAwait(false);
return (<#= string.Join(", ", Enumerable.Range(0, i).Select(x => $"results[{x}]")) #>);
}
return WhenAllAsync(<#= string.Join(", ", Enumerable.Range(1, i).Select(x => $"tasks.T{x}")) #>).GetAwaiter();
}
<# } #>
}
}
================================================
FILE: src/Chell/Extensions/StringExtensions.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace Chell.Extensions
{
public static class StringExtensions
{
///
/// Enumerates lines by converting them to objects as JSON.
///
///
/// Converts to the anonymous type specified in argument.
///
public static IEnumerable AsJsonLines(this IEnumerable lines, T shape, bool skipEmptyLine = true, JsonSerializerOptions? options = null)
{
return AsJsonLines(lines, skipEmptyLine, options);
}
///
/// Enumerates lines by converting them to objects as JSON.
///
public static IEnumerable AsJsonLines(this IEnumerable lines, bool skipEmptyLine = true, JsonSerializerOptions? options = null)
{
return lines.Where(x => !skipEmptyLine || !string.IsNullOrWhiteSpace(x)).Select(x => JsonSerializer.Deserialize(x, options));
}
///
/// Converts the output string to an object as JSON.
///
///
/// Converts to the anonymous type specified in argument.
///
public static T? AsJson(this string json, T shape, JsonSerializerOptions? options = null)
=> AsJson(json, options);
///
/// Converts the output string to an object as JSON.
///
public static T? AsJson(this string json, JsonSerializerOptions? options = null)
=> JsonSerializer.Deserialize(json.ToString(), options);
}
}
================================================
FILE: src/Chell/IO/ChellWrappedStream.cs
================================================
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Chell.IO
{
public partial class ChellWritableStream : ChellWrappedStream
{
private readonly StreamWriter _writer;
public ChellWritableStream(Stream baseStream, Encoding encoding)
: base(baseStream)
{
_writer = new StreamWriter(baseStream, encoding);
_writer.AutoFlush = true;
}
public void Write(byte[] value) => BaseStream.Write(value);
public new void Write(ReadOnlySpan value) => BaseStream.Write(value);
public ValueTask WriteAsync(byte[] value, CancellationToken cancellationToken = default) => BaseStream.WriteAsync(value, cancellationToken);
public new ValueTask WriteAsync(ReadOnlyMemory value, CancellationToken cancellationToken = default) => BaseStream.WriteAsync(value, cancellationToken);
protected override void Dispose(bool disposing)
{
_writer.Dispose();
base.Dispose(disposing);
}
public override async ValueTask DisposeAsync()
{
await _writer.DisposeAsync();
await base.DisposeAsync();
}
}
public partial class ChellReadableStream : ChellWrappedStream
{
private readonly StreamReader _reader;
public ChellReadableStream(Stream baseStream, Encoding encoding)
: base(baseStream)
{
_reader = new StreamReader(baseStream, encoding);
}
public async Task ReadAllBytesAsync(CancellationToken cancellationToken = default)
{
var bufferWriter = new ArrayBufferWriter();
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
var readLen = await BaseStream.ReadAsync(bufferWriter.GetMemory(1024 * 32), cancellationToken);
if (readLen == 0)
{
return bufferWriter.WrittenMemory.ToArray();
}
bufferWriter.Advance(readLen);
}
}
public byte[] ReadAllBytes()
{
var bufferWriter = new ArrayBufferWriter();
while (true)
{
var readLen = BaseStream.Read(bufferWriter.GetSpan(1024 * 32));
if (readLen == 0)
{
return bufferWriter.WrittenMemory.ToArray();
}
bufferWriter.Advance(readLen);
}
}
public async Task ReadToEndAsync()
{
return await _reader.ReadToEndAsync();
}
public string ReadToEnd()
{
return _reader.ReadToEnd();
}
public IEnumerable ReadAllLines()
{
while (!_reader.EndOfStream)
{
var line = _reader.ReadLine();
if (line is null) yield break;
yield return line;
}
}
public async IAsyncEnumerable ReadAllLinesAsync()
{
while (!_reader.EndOfStream)
{
var line = await _reader.ReadLineAsync();
if (line is null) yield break;
yield return line;
}
}
protected override void Dispose(bool disposing)
{
_reader.Dispose();
base.Dispose(disposing);
}
}
public abstract class ChellWrappedStream : Stream
{
private readonly Stream _baseStream;
protected Stream BaseStream => _baseStream;
protected ChellWrappedStream(Stream baseStream)
{
_baseStream = baseStream;
}
#region Stream Implementation
public override void Flush()
{
_baseStream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _baseStream.Read(buffer, offset, count);
}
public override int Read(Span buffer)
{
return _baseStream.Read(buffer);
}
public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _baseStream.ReadAsync(buffer, offset, count, cancellationToken);
}
public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = new CancellationToken())
{
return _baseStream.ReadAsync(buffer, cancellationToken);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _baseStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
_baseStream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
_baseStream.Write(buffer, offset, count);
}
public override void Write(ReadOnlySpan buffer)
{
_baseStream.Write(buffer);
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _baseStream.WriteAsync(buffer, offset, count, cancellationToken);
}
public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = new CancellationToken())
{
return _baseStream.WriteAsync(buffer, cancellationToken);
}
public override bool CanRead => _baseStream.CanRead;
public override bool CanSeek => _baseStream.CanSeek;
public override bool CanWrite => _baseStream.CanWrite;
public override long Length => _baseStream.Length;
public override long Position
{
get => _baseStream.Position;
set => _baseStream.Position = value;
}
#endregion
}
}
================================================
FILE: src/Chell/IO/ChellWritableStream.Generated.cs
================================================
#nullable enable
///
using System;
using System.IO;
using System.Threading.Tasks;
namespace Chell.IO
{
public partial class ChellWritableStream
{
public void Write(string? value) => _writer.Write(value);
public void WriteLine(string? value) => _writer.WriteLine(value);
public Task WriteAsync(string? value) => _writer.WriteAsync(value);
public Task WriteLineAsync(string? value) => _writer.WriteLineAsync(value);
public void Write(char value) => _writer.Write(value);
public void WriteLine(char value) => _writer.WriteLine(value);
public Task WriteAsync(char value) => _writer.WriteAsync(value);
public Task WriteLineAsync(char value) => _writer.WriteLineAsync(value);
public void Write(char[]? value) => _writer.Write(value);
public void WriteLine(char[]? value) => _writer.WriteLine(value);
public Task WriteAsync(char[]? value) => _writer.WriteAsync(value);
public Task WriteLineAsync(char[]? value) => _writer.WriteLineAsync(value);
public void Write(object? value) => _writer.Write(value);
public void WriteLine(object? value) => _writer.WriteLine(value);
public void Write(double value) => _writer.Write(value);
public void WriteLine(double value) => _writer.WriteLine(value);
public void Write(float value) => _writer.Write(value);
public void WriteLine(float value) => _writer.WriteLine(value);
public void Write(long value) => _writer.Write(value);
public void WriteLine(long value) => _writer.WriteLine(value);
public void Write(int value) => _writer.Write(value);
public void WriteLine(int value) => _writer.WriteLine(value);
public void Write(ReadOnlySpan value) => _writer.Write(value);
public void WriteLine(ReadOnlySpan value) => _writer.WriteLine(value);
public Task WriteAsync(ReadOnlyMemory value) => _writer.WriteAsync(value);
public Task WriteLineAsync(ReadOnlyMemory value) => _writer.WriteLineAsync(value);
}
}
================================================
FILE: src/Chell/IO/ChellWritableStream.tt
================================================
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".Generated.cs" #>
<#
var types = new []
{
(0, "string?"),
(0, "char"),
(0, "char[]?"),
(1, "object?"),
(1, "double"),
(1, "float"),
(1, "long"),
(1, "int"),
(1, "ReadOnlySpan"),
(2, "ReadOnlyMemory"),
};
#>
#nullable enable
///
using System;
using System.IO;
using System.Threading.Tasks;
namespace Chell.IO
{
public partial class ChellWritableStream
{
<# foreach (var (target, type) in types) { #>
<# if (target == 0 || target == 1) { #>
public void Write(<#= type #> value) => _writer.Write(value);
public void WriteLine(<#= type #> value) => _writer.WriteLine(value);
<# } #>
<# if (target == 0 || target == 2) { #>
public Task WriteAsync(<#= type #> value) => _writer.WriteAsync(value);
public Task WriteLineAsync(<#= type #> value) => _writer.WriteLineAsync(value);
<# } #>
<# } #>
}
}
================================================
FILE: src/Chell/IO/IConsoleProvider.cs
================================================
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Chell.IO
{
public interface IConsoleProvider
{
Stream OpenStandardInput();
Stream OpenStandardOutput();
Stream OpenStandardError();
Encoding InputEncoding { get; }
Encoding OutputEncoding { get; }
bool IsInputRedirected { get; }
bool IsOutputRedirected { get; }
bool IsErrorRedirected { get; }
TextWriter Out { get; }
TextWriter Error { get; }
}
}
================================================
FILE: src/Chell/IO/LINQPadConsoleProvider.cs
================================================
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipelines;
using System.Text;
using System.Threading.Tasks;
namespace Chell.IO
{
public class LINQPadConsoleProvider : IConsoleProvider
{
private readonly Pipe _pipe;
public Encoding InputEncoding => Console.InputEncoding;
public Encoding OutputEncoding => Console.OutputEncoding;
public bool IsInputRedirected => Console.IsInputRedirected;
public bool IsOutputRedirected => Console.IsOutputRedirected;
public bool IsErrorRedirected => Console.IsErrorRedirected;
public TextWriter Out { get; }
public TextWriter Error { get; }
public LINQPadConsoleProvider()
{
_pipe = new Pipe();
Out = new PipeTextWriter(_pipe.Writer, OutputEncoding);
Error = new PipeTextWriter(_pipe.Writer, OutputEncoding);
var reader = new StreamReader(_pipe.Reader.AsStream());
_ = Task.Run(async () =>
{
Memory buffer = new char[1024];
while (true)
{
var read = await reader.ReadAsync(buffer, default);
if (read != 0)
{
Console.Out.Write(buffer.Span.Slice(0, read));
}
}
});
}
public Stream OpenStandardInput()
=> Console.OpenStandardInput();
public Stream OpenStandardOutput()
=> _pipe.Writer.AsStream(leaveOpen: true);
public Stream OpenStandardError()
=> _pipe.Writer.AsStream(leaveOpen: true);
private class PipeTextWriter : TextWriter
{
private readonly PipeWriter _writer;
public override Encoding Encoding { get; }
public PipeTextWriter(PipeWriter writer, Encoding encoding)
{
_writer = writer;
Encoding = encoding;
}
public override void Write(char value)
{
Span buffer = stackalloc byte[4];
Span c = stackalloc char[1];
c[0] = value;
var written = Encoding.GetBytes(c, buffer);
_writer.Write(buffer.Slice(0, written));
_ = _writer.FlushAsync();
}
}
}
}
================================================
FILE: src/Chell/IO/SystemConsoleProvider.cs
================================================
using System;
using System.IO;
using System.Text;
namespace Chell.IO
{
///
/// Encapsulates console intrinsic members as object.
///
public sealed class SystemConsoleProvider : IConsoleProvider
{
public static IConsoleProvider Instance { get; } = new SystemConsoleProvider();
private SystemConsoleProvider()
{}
public Stream OpenStandardInput()
=> Console.OpenStandardInput();
public Stream OpenStandardOutput()
=> Console.OpenStandardOutput();
public Stream OpenStandardError()
=> Console.OpenStandardError();
public Encoding InputEncoding => Console.InputEncoding;
public Encoding OutputEncoding => Console.OutputEncoding;
public bool IsInputRedirected => Console.IsInputRedirected;
public bool IsOutputRedirected => Console.IsOutputRedirected;
public bool IsErrorRedirected => Console.IsErrorRedirected;
public TextWriter Out => Console.Out;
public TextWriter Error => Console.Error;
}
}
================================================
FILE: src/Chell/Internal/CommandLineHelper.cs
================================================
using System;
using System.Collections;
using System.Linq;
using Chell.IO;
using Chell.Shell;
using Kokuban;
// ReSharper disable CoVariantArrayConversion
namespace Chell.Internal
{
internal class CommandLineHelper
{
public static void WriteCommandLineToConsole(IConsoleProvider console, string commandLine, ChellVerbosity? verbosity = default)
{
verbosity ??= ChellEnvironment.Current.Verbosity;
if (verbosity.Value.HasFlag(ChellVerbosity.CommandLine))
{
var parts = commandLine.Split(' ', 2);
if (LINQPadHelper.RunningOnLINQPad)
{
LINQPadHelper.WriteRawHtml(
$"$ {EscapeHtml(parts[0])}{EscapeHtml((parts.Length > 1 ? " " + parts[1] : string.Empty))}");
}
else
{
console.Out.WriteLine("$ " + (Chalk.BrightGreen + parts[0]) + (parts.Length > 1 ? " " + parts[1] : string.Empty));
}
}
static string EscapeHtml(string s)
=> s.Replace("&", "&").Replace("\"", """).Replace("<", ">");
}
public static string Expand(FormattableString commandLine, IShellExecutor shellExecutor)
{
return string.Format(commandLine.Format.Trim(), commandLine.GetArguments().Select(x =>
{
return x switch
{
ProcessOutput procOutput => shellExecutor.Escape(procOutput.Output.TrimEnd('\n')),
string s => shellExecutor.Escape(s),
IEnumerable enumerable => string.Join(" ", enumerable.OfType