{"id":16359988,"url":"https://github.com/superjmn/dotnetpackaging","last_synced_at":"2026-05-12T00:01:49.836Z","repository":{"id":203571066,"uuid":"709878230","full_name":"SuperJMN/DotnetPackaging","owner":"SuperJMN","description":"Distribute your .NET applications!","archived":false,"fork":false,"pushed_at":"2026-05-03T10:16:55.000Z","size":58922,"stargazers_count":125,"open_issues_count":4,"forks_count":7,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-05-03T12:17:09.024Z","etag":null,"topics":["avalonia","avaloniaui","build","cross-platform","distribute","linux"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SuperJMN.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":"superjmn","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2023-10-25T15:16:05.000Z","updated_at":"2026-05-03T10:13:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"0dde8634-124c-46c1-a080-22d41bb20305","html_url":"https://github.com/SuperJMN/DotnetPackaging","commit_stats":null,"previous_names":["superjmn/dotnetpackaging"],"tags_count":116,"template":false,"template_full_name":null,"purl":"pkg:github/SuperJMN/DotnetPackaging","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SuperJMN%2FDotnetPackaging","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SuperJMN%2FDotnetPackaging/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SuperJMN%2FDotnetPackaging/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SuperJMN%2FDotnetPackaging/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SuperJMN","download_url":"https://codeload.github.com/SuperJMN/DotnetPackaging/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SuperJMN%2FDotnetPackaging/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32917885,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-11T17:09:15.040Z","status":"ssl_error","status_checked_at":"2026-05-11T17:08:45.420Z","response_time":120,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["avalonia","avaloniaui","build","cross-platform","distribute","linux"],"created_at":"2024-10-11T02:10:12.046Z","updated_at":"2026-05-12T00:01:49.818Z","avatar_url":"https://github.com/SuperJMN.png","language":"C#","funding_links":["https://github.com/sponsors/superjmn"],"categories":[],"sub_categories":[],"readme":"# DotnetPackaging\n\nDotnetPackaging helps you turn the publish output of a .NET application into ready-to-ship deliverables for Linux, Windows and macOS. The repository produces two related artifacts:\n\n- **NuGet libraries** (`DotnetPackaging`, `DotnetPackaging.AppImage`, `DotnetPackaging.Deb`, `DotnetPackaging.Msix`, `DotnetPackaging.Dmg`, `DotnetPackaging.Exe`) that expose packaging primitives for tool authors and CI integrations.\n- **A global `dotnet` tool** (`dotnetpackager`) that wraps those libraries with a scriptable command line experience.\n\nSupported formats today: `.AppImage`, `.deb`, `.rpm`, `.msix` (experimental), `.dmg` (experimental) and a Windows self-extracting `.exe` (preview).\n\nBoth flavors share the same code paths, so whatever works in the CLI is also available from your own automation. The best part? Everything is pure .NET with zero native dependencies, so you can crank out packages from whatever OS you’re using without hunting for platform-specific toolchains.\n\n## Why DotnetPackaging\n\nShipping .NET apps shouldn’t require juggling half a dozen platform tools. DotnetPackaging keeps things friendly by giving you one toolbox to generate installers and bundles for the ecosystems your users actually run. No extra daemons, no native SDK rabbit holes—just run the CLI or the libraries, and your bits are ready to share. It’s a laid-back, developer-first way to make sure your app lands everywhere it needs to.\n\n## Repository layout\n- `src/DotnetPackaging`: core abstractions such as metadata models, ELF inspection, icon discovery and option builders.\n- `src/DotnetPackaging.AppImage`: AppImage-specific logic, including AppDir builders and runtime composition.\n- `src/DotnetPackaging.Deb`: helpers to produce Debian control/data archives and emit `.deb` files.\n- `src/DotnetPackaging.Tool`: the `dotnetpackager` CLI that consumes the libraries.\n- `src/DotnetPackaging.DeployerTool` and `src/DotnetPackaging.Deployment`: optional utilities for publishing packages from CI setups.\n\nAll projects target .NET 10.\n\n## Library usage\n\nEvery library works with the `Zafiro` filesystem abstractions so you can build packages from real directories or in-memory containers. The helpers infer reasonable defaults (architecture, executable, icon files, metadata) while still letting you override everything. Use the `*Packager` classes as the entry point; extension methods provide `FromProject` and `PackProject` conveniences.\n\n### AppImage packages\nKey capabilities:\n- Build an AppImage straight from a published directory: no temporary copies, the directory is streamed into the SquashFS runtime.\n- Generate intermediate AppDir structures if you want to tweak the contents before producing the final AppImage.\n- Automatically detect the main executable (ELF inspection) and common icon files, with opt-in overrides.\n\n```csharp\nusing DotnetPackaging.AppImage;\nusing Zafiro.DivineBytes;\nusing Zafiro.DivineBytes.System.IO;\nusing Zafiro.FileSystem.Core;\nusing Zafiro.FileSystem.Local;\n\nvar publishDir = new Directory(new FileSystem().DirectoryInfo.New(\"./bin/Release/net10.0/linux-x64/publish\"));\nvar appRoot = (await publishDir.ToDirectory()).Value;\nvar container = new DirectoryContainer(appRoot);\n\nvar metadata = new AppImagePackagerMetadata();\nmetadata.PackageOptions\n    .WithId(\"com.example.myapp\")\n    .WithName(\"My App\")\n    .WithPackage(\"my-app\")\n    .WithVersion(\"1.0.0\")\n    .WithSummary(\"Cross-platform sample\")\n    .WithComment(\"Longer description shown in desktop menus\");\n\nvar packager = new AppImagePackager();\nvar appImage = await packager.Pack(container.AsRoot(), metadata);\nif (appImage.IsSuccess)\n{\n    await appImage.Value.WriteTo(\"./artifacts/MyApp.appimage\");\n}\n```\n\nFor AppDir workflows, use the CLI subcommands (`appimage appdir` and `appimage from-appdir`).\n\n### Debian packages\nKey capabilities:\n- Build `.deb` archives from any container or directory that resembles the install root of your app.\n- Auto-detect the executable and architecture (with `FromDirectoryOptions` overrides when you know better).\n- Emit `IByteSource` streams so you can persist packages to disk, upload them elsewhere, or plug them into other pipelines.\n- **Install as a systemd service/daemon** with a single method call — generates the unit file, maintainer scripts, and automatic enable/start on install.\n\n```csharp\nusing System.IO.Abstractions;\nusing DotnetPackaging.Deb;\nusing DotnetPackaging;\nusing Zafiro.DivineBytes;\nusing Zafiro.DivineBytes.System.IO;\n\nvar publishDir = new DirectoryContainer(new FileSystem().DirectoryInfo.New(\"./bin/Release/net10.0/linux-x64/publish\"));\nvar options = new FromDirectoryOptions()\n    .WithName(\"My App\")\n    .WithPackage(\"my-app\")\n    .WithVersion(\"1.0.0\")\n    .WithSummary(\"Cross-platform sample app\");\n\nvar packager = new DebPackager();\nvar debResult = await packager.Pack(publishDir.AsRoot(), options);\n\nif (debResult.IsSuccess)\n{\n    await debResult.Value.WriteTo(\"./artifacts/MyApp_1.0.0_amd64.deb\");\n}\n```\n\nTo install the application as a systemd service, call `WithService()`:\n\n```csharp\nvar options = new FromDirectoryOptions()\n    .WithName(\"My API\")\n    .WithPackage(\"my-api\")\n    .WithVersion(\"2.0.0\")\n    .WithSummary(\"Web API backend\")\n    .WithService(svc =\u003e svc\n        .WithType(ServiceType.Notify)\n        .WithRestart(RestartPolicy.Always)\n        .WithUser(\"www-data\")\n        .WithEnvironment(\"DOTNET_ENVIRONMENT=Production\", \"ASPNETCORE_URLS=http://+:5000\"));\n```\n\nThe generated `.deb` will include a systemd unit file at `/lib/systemd/system/{package}.service` and maintainer scripts that `daemon-reload`, `enable`, and `start` the service on install, `stop` and `disable` on removal, and clean up on purge. This is the Linux equivalent of a Windows service — designed so .NET developers don't have to learn systemd internals.\n\n`FromDirectoryOptions` exposes many more helpers (`WithExecutableName`, `WithIcon`, `WithHomepage`, `WithCategories`, `WithMaintainer`, etc.) so you can describe the package metadata you need.\n\n\n\n## `dotnetpackager` CLI\n\nThe CLI is published as `DotnetPackaging.Tool` and installs a `dotnetpackager` command that mirrors the library APIs.\n\n### Install\n```bash\ndotnet tool install --global DotnetPackaging.Tool\n```\n\n### Commands\n\nEvery format command offers two subcommands:\n- **`from-directory`** – package from a pre-published directory (the output of `dotnet publish`).\n- **`from-project`** – publish a .NET project and package in one step.\n\n\u003e **Deprecation notice:** invoking the base command directly with `--directory` (e.g. `dotnetpackager deb --directory`) still works for backward compatibility but is deprecated. Use `deb from-directory` instead. A future release will remove the deprecated form.\n\n| Format | From directory | From project | Extra subcommands |\n|---|---|---|---|\n| **appimage** | `appimage from-directory` | `appimage from-project` | `appdir`, `from-appdir` |\n| **deb** | `deb from-directory` | `deb from-project` | — |\n| **rpm** | `rpm from-directory` | `rpm from-project` | — |\n| **dmg** | `dmg from-directory` | `dmg from-project` | `verify` |\n| **exe** | `exe from-directory` | `exe from-project` | — |\n| **msix** | `msix from-directory` | `msix from-project` | — |\n\nRun `dotnetpackager \u003ccommand\u003e --help` to see the full list of shared options (`--application-name`, `--comment`, `--homepage`, `--keywords`, `--icon`, `--is-terminal`, etc.).\n\nDMG packages auto-generate an `.app/Contents/Info.plist` when the published directory does not already contain an `.app` bundle. By default the generated plist uses CLI/project metadata such as `--application-name`, `--appId`, `--version`, `--vendor`/`--company`, and `--executable-name`. To take full control, pass `--info-plist ./Info.plist` to `dmg from-directory` or `dmg from-project`; that file has precedence over generated metadata. If no CLI plist is supplied, a root `Info.plist` next to the publish output or project is used before falling back to generated metadata. Inside generated metadata, explicit CLI options override project metadata, and project metadata overrides built-in defaults.\n\nDMG root adornments are preserved from the input directory. Root-level `.background`, `.DS_Store`, and `.VolumeIcon.icns` stay at the volume root whether the input already contains an `.app` bundle or DotnetPackaging generates one. With `--with-default-layout`, embedded defaults fill only missing layout pieces such as `.background/Background.png` or `.DS_Store`; with `--with-default-layout false`, no embedded layout files are injected.\n\n### Examples\nBuild an AppImage from a published directory:\n```bash\ndotnetpackager appimage from-directory \\\n  --directory ./bin/Release/net10.0/linux-x64/publish \\\n  --output ./artifacts/MyApp.appimage \\\n  --application-name \"My App\" \\\n  --summary \"Cross-platform sample\" \\\n  --homepage https://example.com\n```\n\nStage an AppDir and inspect it before packaging:\n```bash\ndotnetpackager appimage appdir \\\n  --directory ./bin/Release/net10.0/linux-x64/publish \\\n  --output-dir ./artifacts/MyApp.AppDir\n\n# ...modify the AppDir contents if needed...\n\ndotnetpackager appimage from-appdir \\\n  --directory ./artifacts/MyApp.AppDir \\\n  --output ./artifacts/MyApp.appimage\n```\n\nProduce a Debian package with a custom name and version:\n```bash\ndotnetpackager deb from-directory \\\n  --directory ./bin/Release/net10.0/linux-x64/publish \\\n  --output ./artifacts/MyApp_1.0.0_amd64.deb \\\n  --application-name \"My App\" \\\n  --summary \"Cross-platform sample\" \\\n  --comment \"Longer description\" \\\n  --homepage https://example.com \\\n  --license MIT \\\n  --version 1.0.0\n```\n\nPackage a .NET project as a systemd service (publish + package in one step):\n```bash\ndotnetpackager deb from-project \\\n  --project ./src/MyApi/MyApi.csproj \\\n  --output ./artifacts/myapi.deb \\\n  --service\n```\n\nThat single `--service` flag generates a systemd unit file, maintainer scripts for `daemon-reload`/`enable`/`start` on install and `stop`/`disable` on removal. Sensible defaults (`Type=simple`, `Restart=on-failure`) mean you rarely need anything else, but you can fine-tune:\n\n```bash\ndotnetpackager deb from-project \\\n  --project ./src/MyApi/MyApi.csproj \\\n  --output ./artifacts/myapi.deb \\\n  --service \\\n  --service-type notify \\\n  --service-restart always \\\n  --service-user www-data \\\n  --service-environment DOTNET_ENVIRONMENT=Production \\\n  --service-environment ASPNETCORE_URLS=http://+:5000\n```\n\nThe `--service` flag also works from a pre-published directory:\n```bash\ndotnetpackager deb from-directory \\\n  --directory ./bin/Release/net10.0/linux-x64/publish \\\n  --output ./artifacts/myapi.deb \\\n  --application-name myapi \\\n  --service\n```\n\n| Service option | Default | Values |\n|---|---|---|\n| `--service` | *(off)* | Flag — enables systemd service mode |\n| `--service-type` | `simple` | `simple`, `notify`, `forking`, `oneshot`, `idle` |\n| `--service-restart` | `on-failure` | `no`, `always`, `on-failure`, `on-abnormal`, `on-abort`, `on-watchdog` |\n| `--service-user` | *(none)* | Any Linux username |\n| `--service-environment` | *(none)* | `KEY=VALUE` pairs (repeatable) |\n\nAll commands work on Windows, macOS or Linux, but the produced artifacts target Linux desktops (or Linux servers when using `--service`).\n\n## Working on the repository\n- Use the solution `DotnetPackaging.sln` and .NET SDK 10.0 or later.\n- Unit tests live under `test/` (AppImage, Deb, Msix, etc.).\n- `DotnetPackaging.DeployerTool` automates publishing NuGet packages and GitHub releases; see `azure-pipelines.yml` for a full CI example.\n\n## License\nThe entire project is distributed under the MIT License. See `LICENSE` for details.\n\n## Acknowledgements\n- SquashFS support relies on [NyaFS](https://github.com/teplofizik/nyafs) by Alexey Sonkin.\n- Filesystem abstractions come from the [Zafiro](https://github.com/SuperJMN/Zafiro) toolkit.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuperjmn%2Fdotnetpackaging","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsuperjmn%2Fdotnetpackaging","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuperjmn%2Fdotnetpackaging/lists"}