505 lines
9.2 KiB
Markdown
505 lines
9.2 KiB
Markdown
# Adding Packages Guide
|
|
|
|
How to add new packages to m3ta-nixpkgs.
|
|
|
|
## Overview
|
|
|
|
Packages in m3ta-nixpkgs are organized using a `callPackage` registry pattern. Each package lives in its own directory and is registered centrally.
|
|
|
|
## Quick Start
|
|
|
|
### Using Templates
|
|
|
|
Use the package template for quick setup:
|
|
|
|
```bash
|
|
nix flake init -t .#package my-new-package
|
|
```
|
|
|
|
This creates a template structure in `templates/package/` that you can copy.
|
|
|
|
### Automatic Updates
|
|
|
|
**Important**: This repository uses automated package updates via Gitea Actions and `nix-update`. When adding a new package:
|
|
|
|
- Use any stable, working version for the initial package
|
|
- You don't need to use the absolute latest version
|
|
- The automation will keep the package updated automatically on a weekly basis
|
|
- Review and merge automated update PRs as they come in
|
|
|
|
See the main README.md for more details on the automated update workflow.
|
|
|
|
### Manual Setup
|
|
|
|
1. Create directory: `pkgs/your-package/`
|
|
2. Write `default.nix` with package definition
|
|
3. Register in `pkgs/default.nix`
|
|
|
|
## Package Structure
|
|
|
|
```
|
|
pkgs/your-package/
|
|
├── default.nix # Package definition (required)
|
|
├── source.py # Optional: additional source files
|
|
├── wrapper.sh # Optional: wrapper scripts
|
|
└── README.md # Optional: package documentation
|
|
```
|
|
|
|
## Common Patterns
|
|
|
|
### Rust Package
|
|
|
|
```nix
|
|
{
|
|
lib,
|
|
rustPlatform,
|
|
fetchFromGitHub,
|
|
}:
|
|
rustPlatform.buildRustPackage rec {
|
|
pname = "my-rust-app";
|
|
version = "1.0.0";
|
|
|
|
src = fetchFromGitHub {
|
|
owner = "author";
|
|
repo = "my-rust-app";
|
|
rev = "v${version}";
|
|
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
|
};
|
|
|
|
cargoLock.lockFile = src + "/Cargo.lock";
|
|
|
|
buildInputs = [openssl];
|
|
|
|
nativeBuildInputs = [pkg-config];
|
|
|
|
meta = with lib; {
|
|
description = "My Rust application";
|
|
homepage = "https://github.com/author/my-rust-app";
|
|
license = licenses.mit;
|
|
platforms = platforms.linux;
|
|
mainProgram = "my-rust-app";
|
|
};
|
|
}
|
|
```
|
|
|
|
### Python Package
|
|
|
|
```nix
|
|
{
|
|
lib,
|
|
python3,
|
|
fetchFromGitHub,
|
|
}:
|
|
python3.pkgs.buildPythonPackage rec {
|
|
pname = "my-python-app";
|
|
version = "1.0.0";
|
|
pyproject = true;
|
|
|
|
src = fetchFromGitHub {
|
|
owner = "author";
|
|
repo = "my-python-app";
|
|
rev = "v${version}";
|
|
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
|
};
|
|
|
|
build-system = with python3.pkgs; [setuptools];
|
|
|
|
dependencies = with python3.pkgs; [
|
|
requests
|
|
click
|
|
];
|
|
|
|
optional-dependencies = with python3.pkgs; {
|
|
extras = [pyyaml];
|
|
};
|
|
|
|
doCheck = true;
|
|
|
|
pythonImportsCheck = ["myapp"];
|
|
|
|
meta = with lib; {
|
|
description = "My Python application";
|
|
homepage = "https://github.com/author/my-python-app";
|
|
license = licenses.mit;
|
|
platforms = platforms.linux;
|
|
mainProgram = "my-app";
|
|
};
|
|
}
|
|
```
|
|
|
|
### Shell Script Package
|
|
|
|
```nix
|
|
{
|
|
lib,
|
|
writeShellScriptBin,
|
|
}:
|
|
writeShellScriptBin "my-script" ''
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
echo "Hello from my script!"
|
|
|
|
# Your script logic here
|
|
''
|
|
|
|
# If you need to add dependencies
|
|
{
|
|
lib,
|
|
writeShellApplication,
|
|
bash,
|
|
curl,
|
|
}:
|
|
writeShellApplication {
|
|
name = "my-script";
|
|
runtimeInputs = [bash curl];
|
|
text = ''
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
curl -s https://example.com
|
|
'';
|
|
}
|
|
```
|
|
|
|
### AppImage Package
|
|
|
|
```nix
|
|
{
|
|
lib,
|
|
appimageTools,
|
|
fetchurl,
|
|
}:
|
|
appimageTools.wrapType2 rec {
|
|
name = "my-app";
|
|
version = "1.0.0";
|
|
|
|
src = fetchurl {
|
|
url = "https://github.com/author/my-app/releases/download/v${version}/My-App-${version}.AppImage";
|
|
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
|
};
|
|
|
|
meta = with lib; {
|
|
description = "My AppImage application";
|
|
homepage = "https://github.com/author/my-app";
|
|
license = licenses.unfree;
|
|
platforms = platforms.linux;
|
|
mainProgram = name;
|
|
};
|
|
}
|
|
```
|
|
|
|
### Custom Source with Patch
|
|
|
|
```nix
|
|
{
|
|
lib,
|
|
stdenv,
|
|
fetchFromGitHub,
|
|
fetchpatch,
|
|
buildGoModule,
|
|
}:
|
|
buildGoModule rec {
|
|
pname = "my-go-app";
|
|
version = "1.0.0";
|
|
|
|
src = fetchFromGitHub {
|
|
owner = "author";
|
|
repo = "my-go-app";
|
|
rev = "v${version}";
|
|
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
|
};
|
|
|
|
patches = [
|
|
# Add local patch
|
|
./fix-build.patch
|
|
|
|
# Add patch from URL
|
|
(fetchpatch {
|
|
url = "https://github.com/author/my-app/pull/123.patch";
|
|
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
|
})
|
|
];
|
|
|
|
vendorHash = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=";
|
|
|
|
meta = with lib; {
|
|
description = "My Go application";
|
|
homepage = "https://github.com/author/my-go-app";
|
|
license = licenses.mit;
|
|
platforms = platforms.linux;
|
|
mainProgram = "my-app";
|
|
};
|
|
}
|
|
```
|
|
|
|
### Package with Custom Installation
|
|
|
|
```nix
|
|
{
|
|
lib,
|
|
stdenv,
|
|
fetchFromGitHub,
|
|
makeWrapper,
|
|
}:
|
|
stdenv.mkDerivation rec {
|
|
pname = "my-app";
|
|
version = "1.0.0";
|
|
|
|
src = fetchFromGitHub {
|
|
owner = "author";
|
|
repo = "my-app";
|
|
rev = "v${version}";
|
|
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
|
};
|
|
|
|
nativeBuildInputs = [makeWrapper];
|
|
|
|
buildPhase = ''
|
|
make build
|
|
'';
|
|
|
|
installPhase = ''
|
|
install -Dm755 my-app $out/bin/my-app
|
|
|
|
# Wrap with runtime dependencies
|
|
wrapProgram $out/bin/my-app \
|
|
--prefix PATH : ${lib.makeBinPath [some-dep]}
|
|
'';
|
|
|
|
meta = with lib; {
|
|
description = "My custom application";
|
|
homepage = "https://github.com/author/my-app";
|
|
license = licenses.mit;
|
|
platforms = platforms.linux;
|
|
mainProgram = "my-app";
|
|
};
|
|
}
|
|
```
|
|
|
|
## Registration
|
|
|
|
### Register in `pkgs/default.nix`
|
|
|
|
Add your package to the registry:
|
|
|
|
```nix
|
|
{
|
|
inherit (pkgs) callPackage;
|
|
} rec {
|
|
# Existing packages
|
|
code2prompt = callPackage ./code2prompt {};
|
|
zellij-ps = callPackage ./zellij-ps {};
|
|
|
|
# Your new package
|
|
my-new-package = callPackage ./my-new-package {};
|
|
}
|
|
```
|
|
|
|
### With Custom Arguments
|
|
|
|
If your package needs custom arguments:
|
|
|
|
```nix
|
|
# pkgs/default.nix
|
|
{
|
|
inherit (pkgs) callPackage;
|
|
} rec {
|
|
my-new-package = callPackage ./my-new-package {
|
|
customArg = "value";
|
|
};
|
|
}
|
|
|
|
# pkgs/my-new-package/default.nix
|
|
{
|
|
lib,
|
|
stdenv,
|
|
fetchurl,
|
|
customArg, # This will be passed from the registry
|
|
}:
|
|
stdenv.mkDerivation {
|
|
# ...
|
|
}
|
|
```
|
|
|
|
## Getting Hashes
|
|
|
|
### Using `lib.fakeHash`
|
|
|
|
During development, use `lib.fakeHash` to get the real hash:
|
|
|
|
```nix
|
|
src = fetchFromGitHub {
|
|
owner = "author";
|
|
repo = "my-app";
|
|
rev = "v${version}";
|
|
hash = lib.fakeHash; # Temporary placeholder
|
|
};
|
|
```
|
|
|
|
Build the package:
|
|
|
|
```bash
|
|
nix build .#my-new-package
|
|
```
|
|
|
|
Copy the actual hash from the error message and update the package:
|
|
|
|
```nix
|
|
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Real hash
|
|
```
|
|
|
|
**Important**: Never commit `lib.fakeHash` to the repository.
|
|
|
|
## Testing
|
|
|
|
### Build Package
|
|
|
|
```bash
|
|
nix build .#my-new-package
|
|
```
|
|
|
|
### Test Execution
|
|
|
|
```bash
|
|
nix run .#my-new-package -- --help
|
|
```
|
|
|
|
### Run in Shell
|
|
|
|
```bash
|
|
nix shell .#my-new-package
|
|
my-new-app --version
|
|
```
|
|
|
|
### Linting
|
|
|
|
```bash
|
|
nix develop
|
|
statix check pkgs/my-new-package/
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### Meta Fields
|
|
|
|
Always include complete `meta` information:
|
|
|
|
```nix
|
|
meta = with lib; {
|
|
description = "Short one-line description";
|
|
longDescription = ''
|
|
Longer description explaining what the package does,
|
|
its features, and use cases.
|
|
'';
|
|
homepage = "https://github.com/author/repo";
|
|
changelog = "https://github.com/author/repo/releases/tag/v${version}";
|
|
license = licenses.mit;
|
|
platforms = platforms.linux;
|
|
mainProgram = "program-name";
|
|
};
|
|
```
|
|
|
|
### Dependencies
|
|
|
|
Explicitly declare all dependencies:
|
|
|
|
```nix
|
|
{
|
|
lib,
|
|
stdenv,
|
|
fetchFromGitHub,
|
|
# Runtime dependencies
|
|
openssl,
|
|
curl,
|
|
# Native build dependencies
|
|
pkg-config,
|
|
cmake,
|
|
}:
|
|
```
|
|
|
|
### Versioning
|
|
|
|
Use `rec` to reference `version` in multiple places:
|
|
|
|
```nix
|
|
rec {
|
|
pname = "my-app";
|
|
version = "1.0.0";
|
|
|
|
src = fetchFromGitHub {
|
|
rev = "v${version}";
|
|
# ...
|
|
};
|
|
}
|
|
```
|
|
|
|
### Platform Restrictions
|
|
|
|
If package is platform-specific:
|
|
|
|
```nix
|
|
meta = with lib; {
|
|
# Linux only
|
|
platforms = platforms.linux;
|
|
|
|
# Or specific platforms
|
|
platforms = ["x86_64-linux" "aarch64-linux"];
|
|
|
|
# Or exclude platforms
|
|
broken = stdenv.isDarwin;
|
|
};
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Hash Mismatch
|
|
|
|
Error: `got: sha256-AAAAAAAA... expected: sha256-BBBBBB...`
|
|
|
|
Solution: Copy `got` hash and update package definition.
|
|
|
|
### Dependency Not Found
|
|
|
|
Error: `error: undefined variable 'somedep'`
|
|
|
|
Solution: Add dependency to function arguments and build inputs:
|
|
|
|
```nix
|
|
{
|
|
lib,
|
|
somedep, # Add here
|
|
}:
|
|
stdenv.mkDerivation {
|
|
buildInputs = [somedep]; # Add here
|
|
}
|
|
```
|
|
|
|
### Import Check Failure
|
|
|
|
Error: `error: Python module 'mymodule' not found`
|
|
|
|
Solution: Disable or fix imports check:
|
|
|
|
```nix
|
|
pythonImportsCheck = ["mymodule"]; # Check this is correct
|
|
# Or if importing creates side effects:
|
|
pythonImportsCheck = [];
|
|
```
|
|
|
|
## Examples
|
|
|
|
See existing packages in the repository:
|
|
|
|
- `pkgs/code2prompt/` - Rust package
|
|
- `pkgs/mem0/` - Python package
|
|
- `pkgs/hyprpaper-random/` - Shell script
|
|
- `pkgs/msty-studio/` - AppImage
|
|
- `pkgs/zellij-ps/` - Fetch from Gitea
|
|
|
|
## Next Steps
|
|
|
|
- [Architecture](../ARCHITECTURE.md) - Understanding package organization
|
|
- [Using Modules](./using-modules.md) - If you need to create modules
|
|
- [Contributing](../CONTRIBUTING.md) - Code style and guidelines
|