Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = space
indent_size = 4
quote_type = double
max_line_length = 120

[*.{cs,csproj,props,targets,xml}]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = tab
indent_size = 4
tab_width = 4

[*.cs]
# C# style preferences
csharp_new_line_before_open_brace = none:warning
csharp_new_line_before_else = false:warning
csharp_new_line_before_catch = false:warning
csharp_new_line_before_finally = false:warning
csharp_prefer_braces = true:warning
csharp_style_expression_bodied_methods = when_possible:suggestion
csharp_style_expression_bodied_properties = when_possible:suggestion
csharp_style_namespace_declarations = file_scoped:suggestion
csharp_style_var_elsewhere = false:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
dotnet_analyzer_diagnostic.category-Style.severity = none
dotnet_diagnostic.CA1016.severity = none
dotnet_style_qualification_for_event = false:suggestion
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_property = false:suggestion

# Naming conventions
dotnet_naming_rule.types_should_be_pascal_case.severity = warning
dotnet_naming_rule.types_should_be_pascal_case.symbols = all_types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case_style

dotnet_naming_symbols.all_types.applicable_kinds = class, struct, interface, enum, delegate

dotnet_naming_style.pascal_case_style.capitalization = pascal_case

[**/tests/**]
max_line_length = off
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sh text eol=lf
21 changes: 21 additions & 0 deletions .github/workflows/pr-build-and-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: pr-build-and-test

on:
pull_request:

jobs:
build-and-test:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x

- run: dotnet clean Icod.Host.sln -c Staging
- run: dotnet restore Icod.Host.sln
- run: dotnet build Icod.Host.sln -c Staging --no-restore
- run: dotnet test Icod.Host.sln -c Staging --no-build --logger trx
77 changes: 77 additions & 0 deletions .github/workflows/push-main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: build and publish

on:
push:
branches:
- main

permissions:
id-token: write
contents: read
packages: write

jobs:
build-and-test:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x

- run: dotnet clean Icod.Host.sln -c Release
- run: dotnet restore Icod.Host.sln
- run: dotnet build Icod.Host.sln -c Release --no-restore -p:ContinuousIntegrationBuild=true
- run: dotnet test Icod.Host.sln -c Release --no-build --logger trx

- name: Pack NuGet Package
if: matrix.os == 'windows-latest'
run: dotnet pack Icod.Host.csproj -c Release --no-build -o ./artifacts

- name: Upload Artifact
if: matrix.os == 'windows-latest'
uses: actions/upload-artifact@v4
with:
name: nuget-package
path: ./artifacts/*nupkg

deploy:
needs: build-and-test
runs-on: windows-latest
environment: Release
steps:
- uses: actions/checkout@v4

- uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x

- name: Download Artifact
uses: actions/download-artifact@v4
with:
name: nuget-package
path: ./artifacts

- name: NuGet login (OIDC → temp API key)
uses: NuGet/login@v1
id: login
with:
user: ${{ secrets.NUGET_USER }}

- name: NuGet push
shell: pwsh
run: |
Get-ChildItem "./artifacts/Icod.Host.*.nupkg" | ForEach-Object {
dotnet nuget push $_.FullName --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
}

- name: Push to GitHub Packages
shell: pwsh
run: |
Get-ChildItem "./artifacts/Icod.Host.*.nupkg" | ForEach-Object {
dotnet nuget push $_.FullName --api-key "${{ secrets.GITHUB_TOKEN }}" --source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" --skip-duplicate
}
111 changes: 111 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Contributing to Icod.Host

Thank you for contributing to `Icod.Host`. The library provides neutral,
cross-platform host identity and processor-resource observations. Changes should
preserve factual semantics, explicit platform limitations, and provenance.

## Supported toolchain

- Target framework: `net10.0`.
- Language version: C# 13.
- Nullable reference types and implicit global usings remain enabled.
- Supported CI runners are `windows-latest`, `ubuntu-latest`, and
`macos-latest`.
- Repository text files use UTF-8 with LF line endings.
- Public, protected, and internal types and members should have substantive XML
documentation; use `<inheritdoc/>` where appropriate.

Do not change the target framework, language version, configuration policy, or
repository line-ending convention as part of an unrelated contribution.

## Architecture

`Icod.Host` owns neutral factual observations such as:

- normalized host identity;
- processor counts;
- process affinity or processor-set selection;
- hard CPU quotas;
- processor and NUMA topology;
- observation availability and provenance; and
- narrow platform adapters needed to obtain those facts.

Do not add GNU `hostid`/`nproc` command policy, process control, ProcPs-specific
metrics or `/proc` models, command-line parsing, or command-hosting
infrastructure.

`ObservationFidelity` is also outside this package. Semantic-fidelity policy
belongs to consumers that map factual host observations into higher-level
cross-platform models.

The package should remain free of dependencies on `Icod.CommandFramework`,
`Icod.CoreUtils`, and `Icod.ProcPs`.

## C# style

Follow `.editorconfig` and the surrounding source. In particular:

- use tabs for C# indentation;
- use 1TBS braces and always brace conditional and loop bodies;
- use PascalCase for types and members and camelCase for locals and parameters;
- validate public, protected, and internal method parameters at entry;
- keep nullable flow explicit rather than suppressing warnings casually;
- propagate `CancellationToken` through asynchronous work; and
- avoid unrelated formatting churn.

Unsupported platform behavior must remain explicit. Do not fabricate Unix
capabilities or substitute unrelated measurements merely to return a value.

## Tests

Add or update tests for changed behavior. Important cases include:

- deterministic host-ID normalization;
- availability/provenance behavior;
- Linux CPU-list parsing;
- cgroup v1 and v2 quota parsing;
- affinity descriptor validation;
- processor quota validation;
- provider injection and cancellation; and
- controlled system-provider behavior on Windows, Linux, and macOS.

Tests must not write to standard output or standard error unless explicitly
communicating with another process. Keep any temporary resources uniquely named
and delete only resources owned by the test.

## Build and validation

From the repository root:

```text
dotnet clean Icod.Host.sln -c Debug
dotnet restore Icod.Host.sln
dotnet build Icod.Host.sln -c Debug --no-restore
dotnet test Icod.Host.sln -c Debug --no-build
```

Before merge or release, also validate Release:

```text
dotnet clean Icod.Host.sln -c Release
dotnet restore Icod.Host.sln
dotnet build Icod.Host.sln -c Release --no-restore
dotnet test Icod.Host.sln -c Release --no-build
```

`build.cmd` and `build.sh` may be used for the standard local sequence. Pull
requests run Staging across all three CI operating systems; pushes to `main`
run Release and publish only after the complete Release matrix succeeds.

## Pull requests and commits

Keep changes focused. A pull request should identify:

- the factual host-resource contract being changed;
- important platform-specific behavior;
- added or changed tests;
- build/test commands and platforms used; and
- intentionally unsupported or deferred behavior.

Use concise imperative commit subjects. Discuss cross-package ownership changes
before introducing a new shared abstraction.
89 changes: 89 additions & 0 deletions Icod.Host.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Copyright>Copyright (c) 2026 Timothy J. Bruce</Copyright>
<LangVersion>13.0</LangVersion>
<OutputType>Library</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<AssemblyName>Icod.Host</AssemblyName>
<RootNamespace>Icod.Host</RootNamespace>
<Configurations>Debug;Release;Staging</Configurations>
<Version>1.0.0</Version>
</PropertyGroup>
<PropertyGroup Condition=" '$(PlatformTarget)' == '' ">
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<ErrorReport>prompt</ErrorReport>
<WarningLevel>2</WarningLevel>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<SignAssembly>false</SignAssembly>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Staging' ">
<ErrorReport>prompt</ErrorReport>
<WarningLevel>3</WarningLevel>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>TRACE</DefineConstants>
<SignAssembly>false</SignAssembly>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
<SignAssembly>false</SignAssembly>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsNotAsErrors>CS1591</WarningsNotAsErrors>
</PropertyGroup>
<PropertyGroup>
<PackageVersion>1.0.0</PackageVersion>
<PackageReleaseNotes>Initial standalone host identity and processor-resource observation release.</PackageReleaseNotes>
<Authors>Timothy J. Bruce</Authors>
<Description>Cross-platform .NET host resource observations for normalized host identity, processor counts, affinity, CPU quotas, topology, NUMA, and provenance.</Description>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<IncludeContentInPack>true</IncludeContentInPack>
<IncludeSymbols>True</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<Deterministic>true</Deterministic>
<PackageTags>host;host-resources;system-information;processor;cpu;cpu-affinity;cpu-quota;processor-topology;numa;host-id;machine-id;cgroup;job-object;sysctl;hardware;resource-observation;cross-platform;dotnet;csharp;system-resources</PackageTags>
<PackageProjectUrl>https://github.com/uniblab/Icod.Host</PackageProjectUrl>
<RepositoryUrl>https://github.com/uniblab/Icod.Host</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageIcon>icon.png</PackageIcon>
<GenerateAppxPackageOnBuild>False</GenerateAppxPackageOnBuild>
</PropertyGroup>
<ItemGroup>
<Compile Include="src\**\*.cs" />
<EmbeddedResource Remove="tests\**" />
<None Remove="tests\**" />
<None Include="icon.png" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<Content Include="README.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>$(AssemblyName).README.md</TargetPath>
<Pack>true</Pack>
<PackagePath>\</PackagePath>
</Content>
<Content Include="LICENSE">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>$(AssemblyName).LICENSE.txt</TargetPath>
<Pack>true</Pack>
<PackagePath>\</PackagePath>
</Content>
</ItemGroup>
</Project>
Loading
Loading