diff --git a/README.md b/README.md index f3b34e1..147c580 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,8 @@ m3ta-nixpkgs/ │ ├── default.nix # Library entry point │ └── ports.nix # Port management utilities ├── examples/ # Usage examples -│ └── ports/ # Port management examples -│ ├── README.md -│ ├── nixos-example.nix -│ ├── home-manager-example.nix -│ └── flake-example.nix +│ ├── home-manager-standalone.nix +│ └── nixos-configuration.nix └── templates/ # Templates for new packages/modules ``` @@ -391,14 +388,15 @@ For advanced use cases, you can use the underlying library functions without the ### Documentation -See comprehensive examples and documentation: +See library documentation: -- `examples/ports/README.md` - Complete guide with all features -- `examples/ports/nixos-example.nix` - Full NixOS configuration example -- `examples/ports/home-manager-example.nix` - Full Home Manager configuration example -- `examples/ports/flake-example.nix` - Complete multi-host flake setup - `lib/ports.nix` - Library source code with inline documentation +Example configurations: + +- `examples/nixos-configuration.nix` - NixOS configuration example +- `examples/home-manager-standalone.nix` - Home Manager configuration example + ## Available Packages | Package | Description | @@ -417,4 +415,4 @@ Individual packages may have their own licenses. Check each package's `meta.lice ## Maintainer -[@m3tam3re](https://github.com/m3tam3re) +[@m3tam3re](https://m3ta.dev) diff --git a/examples/ports-example.nix b/examples/ports-example.nix deleted file mode 100644 index aa91b0c..0000000 --- a/examples/ports-example.nix +++ /dev/null @@ -1,180 +0,0 @@ -# Example: Using the port management library -# -# This example demonstrates how to use the m3ta-nixpkgs port management -# utilities to centralize port configuration across multiple hosts. -{ - inputs, - system, - ... -}: let - # Import the library - m3taLib = inputs.m3ta-nixpkgs.lib.${system}; - - # Define all your ports in one central place - # This makes it easy to see and manage all port assignments - myPortsConfig = { - # Default ports for all services - ports = { - # Web services - nginx = 80; - nginx-ssl = 443; - homepage = 8080; - grafana = 3000; - - # Monitoring - prometheus = 9090; - node-exporter = 9100; - loki = 3100; - - # Development - dev-server = 8000; - dev-api = 8001; - - # Media - jellyfin = 8096; - transmission = 9091; - - # Other services - ssh = 22; - gitea = 3001; - }; - - # Host-specific overrides - # Use this when you need different ports on different machines - hostPorts = { - # On the laptop, run nginx on unprivileged port - laptop = { - nginx = 8080; - nginx-ssl = 8443; - }; - - # On the server, override specific services - server = { - homepage = 3002; - dev-server = 3003; - }; - - # On a VM, use different ports to avoid conflicts - vm = { - nginx = 8888; - grafana = 4000; - prometheus = 9999; - }; - }; - }; - - # Create the port helper functions - ports = m3taLib.ports.mkPortHelpers myPortsConfig; - - # You can also get your hostname dynamically - # hostname = config.networking.hostName; - hostname = "laptop"; # or "server" or "vm" -in { - # ============================================================================ - # Example 1: Using in NixOS configuration - # ============================================================================ - - # Simple usage: get port for current host - services.nginx.defaultHTTPListenPort = ports.getPort "nginx" hostname; - services.nginx.defaultSSLListenPort = ports.getPort "nginx-ssl" hostname; - - services.grafana.settings.server.http_port = ports.getPort "grafana" hostname; - services.prometheus.port = ports.getPort "prometheus" hostname; - - # Without host override (uses default port) - services.openssh.ports = [(ports.getPort "ssh" null)]; - - # Or use getDefaultPort helper for cleaner syntax - services.gitea.settings.server.HTTP_PORT = - m3taLib.ports.getDefaultPort myPortsConfig "gitea"; - - # ============================================================================ - # Example 2: Using in Home Manager configuration - # ============================================================================ - - # Configure development environment with correct ports - home.sessionVariables = { - DEV_SERVER_PORT = toString (ports.getPort "dev-server" hostname); - DEV_API_PORT = toString (ports.getPort "dev-api" hostname); - }; - - # ============================================================================ - # Example 3: Advanced usage - get all ports for current host - # ============================================================================ - - # Get merged view of all ports (defaults + host overrides) - environment.etc."service-ports.json".text = - builtins.toJSON (ports.getHostPorts hostname); - - # This creates a file at /etc/service-ports.json containing: - # { - # "nginx": 8080, // overridden on laptop - # "nginx-ssl": 8443, // overridden on laptop - # "homepage": 8080, // default - # "grafana": 3000, // default - # ... - # } - - # ============================================================================ - # Example 4: Using in systemd services - # ============================================================================ - - systemd.services.my-custom-service = { - description = "My Custom Service"; - after = ["network.target"]; - wantedBy = ["multi-user.target"]; - - environment = { - PORT = toString (ports.getPort "homepage" hostname); - }; - - serviceConfig = { - ExecStart = "/path/to/service --port ${toString (ports.getPort "homepage" hostname)}"; - }; - }; - - # ============================================================================ - # Example 5: Conditional configuration based on host - # ============================================================================ - - # You can use the same port config across all your machines - # and they'll automatically use the right ports - services.jellyfin = { - enable = true; - # Will use 8096 on all hosts (no override defined) - }; - - # ============================================================================ - # Example 6: List all configured services - # ============================================================================ - - # Useful for debugging or documentation - environment.etc."configured-services.txt".text = - builtins.concatStringsSep "\n" ports.listServices; - - # ============================================================================ - # Example 7: Using in a flake-based configuration - # ============================================================================ - - # In your flake.nix: - # - # { - # inputs = { - # nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - # m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs"; - # }; - # - # outputs = { self, nixpkgs, m3ta-nixpkgs, ... }: { - # nixosConfigurations.laptop = nixpkgs.lib.nixosSystem { - # system = "x86_64-linux"; - # specialArgs = { - # inherit inputs system; - # }; - # modules = [ - # ./configuration.nix - # ./ports-config.nix # Import this example file - # ]; - # }; - # }; - # } -} diff --git a/modules/home-manager/ports.nix b/modules/home-manager/ports.nix index 7526ea9..3815ea4 100644 --- a/modules/home-manager/ports.nix +++ b/modules/home-manager/ports.nix @@ -55,10 +55,8 @@ with lib; let cfg = config.m3ta.ports; - # Import the ports library portsLib = import ../../lib/ports.nix {inherit lib;}; - # Create port helpers from the configuration portHelpers = if cfg.enable then @@ -74,168 +72,71 @@ in { definitions = mkOption { type = types.attrsOf types.port; default = {}; - example = literalExpression '' - { - vscodium = 8080; - jupyter = 8888; - dev-server = 3000; - local-api = 8000; - } - ''; - description = '' - Default port definitions for user services. - These ports will be used unless overridden by host-specific settings. - ''; + description = "Default port definitions for user services."; }; hostOverrides = mkOption { type = types.attrsOf (types.attrsOf types.port); default = {}; - example = literalExpression '' - { - laptop = { - dev-server = 3001; - vscodium = 8081; - }; - desktop = { - jupyter = 9999; - }; - } - ''; - description = '' - Host-specific port overrides. - Keys are hostnames, values are attribute sets of service-name to port mappings. - ''; + description = "Host-specific port overrides."; }; currentHost = mkOption { type = types.nullOr types.str; default = null; - example = "laptop"; - description = '' - The current hostname to use for port resolution. - Set to null to disable host-specific overrides. - - Note: In Home Manager, you may need to set this manually unless - you pass config.networking.hostName from your NixOS configuration. - ''; + description = "Hostname to use for port resolution."; }; - # Computed option - provides access to port helpers + # Internal computed options get = mkOption { - type = types.functionTo types.port; + type = types.raw; readOnly = true; internal = true; - description = '' - Function to get a port for a service. - Automatically uses the current host for overrides. - ''; }; - getForHost = mkOption { - type = types.functionTo (types.functionTo types.port); + type = types.raw; readOnly = true; internal = true; - description = '' - Function to get a port for a service on a specific host. - Usage: config.m3ta.ports.getForHost "hostname" "service" - ''; }; - all = mkOption { type = types.attrsOf types.port; readOnly = true; internal = true; - description = '' - All ports for the current host (defaults merged with overrides). - ''; }; - allForHost = mkOption { - type = types.functionTo (types.attrsOf types.port); + type = types.raw; readOnly = true; internal = true; - description = '' - Function to get all ports for a specific host. - Usage: config.m3ta.ports.allForHost "hostname" - ''; }; - services = mkOption { type = types.listOf types.str; readOnly = true; internal = true; - description = '' - List of all defined service names. - ''; }; - # Convenience option for generating shell variables + # Env var generation generateEnvVars = mkOption { type = types.bool; default = false; - example = true; - description = '' - Whether to automatically generate environment variables for all ports. - Variables will be named as: PORT_ (uppercase, dashes to underscores). - - Example: service "dev-server" becomes PORT_DEV_SERVER - ''; + description = "Generate environment variables for all ports."; }; envVarPrefix = mkOption { type = types.str; default = "PORT_"; - example = "MY_APP_PORT_"; - description = '' - Prefix for generated environment variables when generateEnvVars is enabled. - ''; + description = "Prefix for generated environment variables."; }; }; config = mkIf cfg.enable { - assertions = [ - { - assertion = cfg.definitions != {}; - message = "m3ta.ports.definitions must not be empty when m3ta.ports.enable is true"; - } - ]; + m3ta.ports.get = service: portHelpers.getPort service cfg.currentHost; + m3ta.ports.getForHost = host: service: portHelpers.getPort service host; + m3ta.ports.all = portHelpers.getHostPorts cfg.currentHost; + m3ta.ports.allForHost = portHelpers.getHostPorts; + m3ta.ports.services = portHelpers.listServices; - m3ta.ports = { - # Function to get port for current host - get = service: - assert assertMsg (portHelpers != null) "Port helpers not initialized"; - assert assertMsg (cfg.definitions ? ${service}) "Service '${service}' not defined in m3ta.ports.definitions"; - portHelpers.getPort service cfg.currentHost; - - # Function to get port for specific host - getForHost = host: service: - assert assertMsg (portHelpers != null) "Port helpers not initialized"; - assert assertMsg (cfg.definitions ? ${service}) "Service '${service}' not defined in m3ta.ports.definitions"; - portHelpers.getPort service host; - - # All ports for current host - all = - if portHelpers != null - then portHelpers.getHostPorts cfg.currentHost - else {}; - - # Function to get all ports for specific host - allForHost = host: - assert assertMsg (portHelpers != null) "Port helpers not initialized"; - portHelpers.getHostPorts host; - - # List all services - services = - if portHelpers != null - then portHelpers.listServices - else []; - }; - - # Optional: Automatically generate environment variables for all ports home.sessionVariables = mkIf cfg.generateEnvVars ( let - # Convert service name to env var name: "dev-server" -> "DEV_SERVER" toEnvVarName = service: cfg.envVarPrefix + (lib.toUpper (builtins.replaceStrings ["-"] ["_"] service)); in @@ -248,14 +149,11 @@ in { ) ); - # Create a JSON file with all ports for easy inspection - home.file.".config/m3ta/ports.json" = { - text = builtins.toJSON { - hostname = cfg.currentHost; - ports = cfg.all; - allDefinitions = cfg.definitions; - hostOverrides = cfg.hostOverrides; - }; + home.file.".config/m3ta/ports.json".text = builtins.toJSON { + hostname = cfg.currentHost; + ports = cfg.all; + allDefinitions = cfg.definitions; + hostOverrides = cfg.hostOverrides; }; }; } diff --git a/modules/nixos/ports.nix b/modules/nixos/ports.nix index 5e1b14a..4ff4816 100644 --- a/modules/nixos/ports.nix +++ b/modules/nixos/ports.nix @@ -45,16 +45,13 @@ { config, lib, - pkgs, ... }: with lib; let cfg = config.m3ta.ports; - # Import the ports library portsLib = import ../../lib/ports.nix {inherit lib;}; - # Create port helpers from the configuration portHelpers = if cfg.enable then @@ -70,150 +67,58 @@ in { definitions = mkOption { type = types.attrsOf types.port; default = {}; - example = literalExpression '' - { - nginx = 80; - grafana = 3000; - prometheus = 9090; - ssh = 22; - } - ''; - description = '' - Default port definitions for services. - These ports will be used unless overridden by host-specific settings. - ''; + description = "Default port definitions for services."; }; hostOverrides = mkOption { type = types.attrsOf (types.attrsOf types.port); default = {}; - example = literalExpression '' - { - laptop = { - nginx = 8080; - ssh = 2222; - }; - server = { - nginx = 443; - }; - } - ''; - description = '' - Host-specific port overrides. - Keys are hostnames, values are attribute sets of service-name to port mappings. - ''; + description = "Host-specific port overrides."; }; currentHost = mkOption { - type = types.nullOr types.str; + type = types.str; default = config.networking.hostName; - defaultText = literalExpression "config.networking.hostName"; - example = "laptop"; - description = '' - The current hostname to use for port resolution. - Defaults to the system's hostname. - Set to null to disable host-specific overrides. - ''; + description = "Hostname to use for port resolution."; }; - # Computed option - provides access to port helpers + # Internal computed options get = mkOption { - type = types.functionTo types.port; + type = types.raw; readOnly = true; internal = true; - description = '' - Function to get a port for a service. - Automatically uses the current host for overrides. - ''; }; getForHost = mkOption { - type = types.functionTo (types.functionTo types.port); + type = types.raw; readOnly = true; internal = true; - description = '' - Function to get a port for a service on a specific host. - Usage: config.m3ta.ports.getForHost "hostname" "service" - ''; }; all = mkOption { type = types.attrsOf types.port; readOnly = true; internal = true; - description = '' - All ports for the current host (defaults merged with overrides). - ''; }; allForHost = mkOption { - type = types.functionTo (types.attrsOf types.port); + type = types.raw; readOnly = true; internal = true; - description = '' - Function to get all ports for a specific host. - Usage: config.m3ta.ports.allForHost "hostname" - ''; }; services = mkOption { type = types.listOf types.str; readOnly = true; internal = true; - description = '' - List of all defined service names. - ''; }; }; config = mkIf cfg.enable { - assertions = [ - { - assertion = cfg.definitions != {}; - message = "m3ta.ports.definitions must not be empty when m3ta.ports.enable is true"; - } - ]; - - m3ta.ports = { - # Function to get port for current host - get = service: - assert assertMsg (portHelpers != null) "Port helpers not initialized"; - assert assertMsg (cfg.definitions ? ${service}) "Service '${service}' not defined in m3ta.ports.definitions"; - portHelpers.getPort service cfg.currentHost; - - # Function to get port for specific host - getForHost = host: service: - assert assertMsg (portHelpers != null) "Port helpers not initialized"; - assert assertMsg (cfg.definitions ? ${service}) "Service '${service}' not defined in m3ta.ports.definitions"; - portHelpers.getPort service host; - - # All ports for current host - all = - if portHelpers != null - then portHelpers.getHostPorts cfg.currentHost - else {}; - - # Function to get all ports for specific host - allForHost = host: - assert assertMsg (portHelpers != null) "Port helpers not initialized"; - portHelpers.getHostPorts host; - - # List all services - services = - if portHelpers != null - then portHelpers.listServices - else []; - }; - - # Optional: Create a JSON file with all ports for easy inspection - environment.etc."m3ta/ports.json" = mkIf cfg.enable { - text = builtins.toJSON { - hostname = cfg.currentHost; - ports = cfg.all; - allDefinitions = cfg.definitions; - hostOverrides = cfg.hostOverrides; - }; - mode = "0444"; - }; + m3ta.ports.get = service: portHelpers.getPort service cfg.currentHost; + m3ta.ports.getForHost = host: service: portHelpers.getPort service host; + m3ta.ports.all = portHelpers.getHostPorts cfg.currentHost; + m3ta.ports.allForHost = portHelpers.getHostPorts; + m3ta.ports.services = portHelpers.listServices; }; }