|
| 1 | +# Architecture |
| 2 | + |
| 3 | +This document describes the architecture and design of the DotnetToolWrapper project. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +DotnetToolWrapper is a .NET console application that serves as a universal launcher for native applications packaged |
| 8 | +as [.NET Tools](https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools). It enables developers to distribute |
| 9 | +platform-specific native executables through the .NET tool ecosystem. |
| 10 | + |
| 11 | +## Problem Statement |
| 12 | + |
| 13 | +The .NET tool ecosystem provides a convenient way to distribute and install command-line tools globally or locally |
| 14 | +within projects. However, .NET tools are inherently limited to .NET applications. Many useful command-line tools are |
| 15 | +written in other languages (C, C++, Rust, Go, etc.) and compiled to native executables. DotnetToolWrapper bridges this |
| 16 | +gap by providing a managed .NET entry point that launches the appropriate native executable for the current platform. |
| 17 | + |
| 18 | +## High-Level Architecture |
| 19 | + |
| 20 | +```mermaid |
| 21 | +flowchart TB |
| 22 | + subgraph package[".NET Tool Package"] |
| 23 | + settings["DotnetToolSettings.xml<br/>Defines tool command name and entry point"] |
| 24 | + |
| 25 | + subgraph wrapper["DemaConsulting.DotnetToolWrapper.dll<br/>(This Application)"] |
| 26 | + step1["1. Detect OS and Architecture"] |
| 27 | + step2["2. Read DotnetToolWrapper.json"] |
| 28 | + step3["3. Locate native executable"] |
| 29 | + step4["4. Launch native executable"] |
| 30 | + step5["5. Return exit code"] |
| 31 | + |
| 32 | + step1 --> step2 --> step3 --> step4 --> step5 |
| 33 | + end |
| 34 | + |
| 35 | + config["DotnetToolWrapper.json<br/>Maps platforms to executables<br/><br/>{<br/> 'win-x64': { 'program': 'win-x64/tool.exe' },<br/> 'linux-x64': { 'program': 'linux-x64/tool' },<br/> 'osx-arm64': { 'program': 'osx-arm64/tool' }<br/>}"] |
| 36 | + |
| 37 | + natives["Native Executables<br/><br/>win-x64/tool.exe (Windows x64)<br/>linux-x64/tool (Linux x64)<br/>osx-arm64/tool (macOS ARM64)<br/>..."] |
| 38 | + |
| 39 | + settings --> wrapper |
| 40 | + wrapper --> config |
| 41 | + config --> natives |
| 42 | + end |
| 43 | +``` |
| 44 | + |
| 45 | +## Core Components |
| 46 | + |
| 47 | +### Program.cs |
| 48 | + |
| 49 | +The main application logic consists of several key functions: |
| 50 | + |
| 51 | +#### Platform Detection |
| 52 | + |
| 53 | +- **`GetOs()`**: Detects the operating system (Windows, Linux, FreeBSD, macOS) |
| 54 | +- **`GetArchitecture()`**: Detects the CPU architecture (x86, x64, ARM, ARM64, WASM, S390x) |
| 55 | +- **`GetTarget()`**: Combines OS and architecture into a target string (e.g., "win-x64", "linux-arm64") |
| 56 | + |
| 57 | +#### Configuration Management |
| 58 | + |
| 59 | +The application reads `DotnetToolWrapper.json` to determine which native executable to launch for the detected platform. |
| 60 | +This JSON file is located in the same directory as the wrapper DLL. |
| 61 | + |
| 62 | +#### Process Execution |
| 63 | + |
| 64 | +The wrapper locates the native executable, constructs a process with the original command-line arguments, and executes |
| 65 | +it in the current working directory. The wrapper then waits for the process to complete and returns its exit code. |
| 66 | + |
| 67 | +## Configuration Schema |
| 68 | + |
| 69 | +### DotnetToolWrapper.json |
| 70 | + |
| 71 | +The configuration file uses a simple JSON structure: |
| 72 | + |
| 73 | +```json |
| 74 | +{ |
| 75 | + "<target-string>": { |
| 76 | + "program": "<path-to-executable>" |
| 77 | + } |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +- **Target String**: Combination of OS and architecture (e.g., "win-x64", "linux-arm64") |
| 82 | +- **Program Path**: Relative or absolute path to the native executable |
| 83 | + - Relative paths are resolved from the wrapper's installation directory |
| 84 | + - Environment variables are expanded |
| 85 | + |
| 86 | +### Supported Target Strings |
| 87 | + |
| 88 | +| OS | Architectures | Notes | |
| 89 | +|---------|--------------------------------------------------|---------------------------------| |
| 90 | +| win | x86, x64, arm, arm64 | Windows platforms | |
| 91 | +| linux | x86, x64, arm, arm64, s390x | Linux distributions | |
| 92 | +| freebsd | x86, x64, arm, arm64 | FreeBSD platforms | |
| 93 | +| osx | x64, arm64 | macOS platforms | |
| 94 | +| browser | wasm | WebAssembly (experimental) | |
| 95 | + |
| 96 | +## Design Decisions |
| 97 | + |
| 98 | +### Multi-Framework Targeting |
| 99 | + |
| 100 | +The application targets .NET 8.0, 9.0, and 10.0 to ensure broad compatibility across different .NET installations. |
| 101 | +This allows the tool to work with both current and recent .NET SDK versions. |
| 102 | + |
| 103 | +### Minimal Dependencies |
| 104 | + |
| 105 | +The application has no external dependencies beyond the .NET standard library. This keeps the package size small and |
| 106 | +reduces potential compatibility issues. |
| 107 | + |
| 108 | +### Process Execution Model |
| 109 | + |
| 110 | +The wrapper uses `ProcessStartInfo` with `UseShellExecute = false` to directly execute the native program without |
| 111 | +involving the system shell. This provides better security and more predictable behavior across platforms. |
| 112 | + |
| 113 | +### Exit Code Propagation |
| 114 | + |
| 115 | +The wrapper exits with the same exit code as the wrapped native executable, ensuring that build scripts and automation |
| 116 | +tools can correctly detect success or failure. |
| 117 | + |
| 118 | +### Working Directory Preservation |
| 119 | + |
| 120 | +The wrapper executes the native program in the user's current working directory, not in the installation directory. |
| 121 | +This ensures that relative file paths in command-line arguments work as expected. |
| 122 | + |
| 123 | +## Extension Points |
| 124 | + |
| 125 | +### Environment Variables |
| 126 | + |
| 127 | +The `program` path in the configuration supports environment variable expansion using standard .NET |
| 128 | +`Environment.ExpandEnvironmentVariables()`. This allows for dynamic configuration based on the runtime environment. |
| 129 | + |
| 130 | +### Future Enhancements |
| 131 | + |
| 132 | +Potential future extensions could include: |
| 133 | + |
| 134 | +- Custom environment variable injection |
| 135 | +- Pre-launch and post-launch hooks |
| 136 | +- Configuration-based argument transformation |
| 137 | +- Logging and diagnostics options |
| 138 | + |
| 139 | +## Security Considerations |
| 140 | + |
| 141 | +- The wrapper does not validate or sanitize command-line arguments; they are passed directly to the native executable |
| 142 | +- The configuration file must be trusted, as it specifies which executables to run |
| 143 | +- The wrapper should be distributed with native executables from trusted sources |
| 144 | +- Package creators should scan native executables for malware before distribution |
| 145 | + |
| 146 | +## Performance Characteristics |
| 147 | + |
| 148 | +- **Startup Overhead**: Minimal (< 50ms on modern hardware) |
| 149 | +- **Memory Footprint**: Small (~20-30 MB for the .NET runtime + wrapper) |
| 150 | +- **CPU Usage**: Negligible (the wrapper is idle while the native process runs) |
| 151 | + |
| 152 | +## Testing Strategy |
| 153 | + |
| 154 | +The project does not currently include automated tests. Testing is performed through: |
| 155 | + |
| 156 | +1. Manual testing on target platforms (Windows, Linux, macOS) |
| 157 | +2. Integration testing with sample .NET tool packages |
| 158 | +3. CI/CD builds that verify compilation for all target frameworks |
| 159 | + |
| 160 | +## Build and Release Process |
| 161 | + |
| 162 | +The project uses GitHub Actions for CI/CD: |
| 163 | + |
| 164 | +1. **Build Workflow**: Compiles the application for all target frameworks |
| 165 | +2. **SBOM Generation**: Creates Software Bill of Materials for transparency |
| 166 | +3. **Artifact Publishing**: Publishes build artifacts for packaging |
| 167 | +4. **Release Workflow**: Creates releases with versioned artifacts |
| 168 | + |
| 169 | +## Related Documentation |
| 170 | + |
| 171 | +- [README.md](README.md) - Usage instructions and examples |
| 172 | +- [CONTRIBUTING.md](CONTRIBUTING.md) - Contribution guidelines |
| 173 | +- [SECURITY.md](SECURITY.md) - Security policy |
0 commit comments