datapass 0.1.0

CLI tool to fetch and display mobile data usage from datapass.de
Documentation
{
  nixConfig = {
    extra-substituters = ["https://datapass.cachix.org"];
    extra-trusted-public-keys = ["datapass.cachix.org-1:OgAST6ZcreyRESQflFWqPACL4uQnoEDfl5Nl8DN37bo="];
  };

  description = "datapass - CLI tool to fetch and display mobile data usage from datapass.de";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    rust-overlay = {
      url = "github:oxalica/rust-overlay";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    crane = {
      url = "github:ipetkov/crane";
    };
    treefmt-nix = {
      url = "github:numtide/treefmt-nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    git-hooks = {
      url = "github:cachix/git-hooks.nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = {
    self,
    nixpkgs,
    flake-utils,
    rust-overlay,
    crane,
    treefmt-nix,
    git-hooks,
  }:
    flake-utils.lib.eachSystem [
      "x86_64-linux"
      "aarch64-linux"
      "i686-linux"
      "aarch64-darwin"
      "x86_64-darwin"
    ] (
      system: let
        overlays = [(import rust-overlay)];
        pkgs = import nixpkgs {
          inherit system overlays;
        };

        # Rust toolchain
        rustToolchain = pkgs.rust-bin.stable.latest.default.override {
          extensions = ["rust-src" "rust-analyzer" "clippy"];
        };

        # Crane lib for building Rust projects
        craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;

        # Source filtering
        src = craneLib.cleanCargoSource (craneLib.path ./.);

        # Common arguments for crane
        commonArgs = {
          inherit src;
          strictDeps = true;

          pname = "datapass";
          version = "0.1.0";

          buildInputs = with pkgs;
            (pkgs.lib.optionals (!pkgs.stdenv.isDarwin) [
              openssl
            ])
            ++ pkgs.lib.optionals pkgs.stdenv.isDarwin (
              with pkgs.darwin.apple_sdk.frameworks; [
                Security
                SystemConfiguration
              ]
            );

          nativeBuildInputs = with pkgs; [
            pkg-config
          ];
        };

        # Build dependencies only (for caching)
        cargoArtifacts = craneLib.buildDepsOnly commonArgs;

        # Build the actual crate
        datapass = craneLib.buildPackage (commonArgs
          // {
            inherit cargoArtifacts;
            doCheck = true;
          });

        # Docker image (stream to avoid materializing tarball on disk)
        # Usage:
        #   nix build .#dockerImage && ./result | docker load
        #   nix build .#dockerImage && ./result | skopeo copy docker-archive:/dev/stdin docker://docker.io/youruser/datapass:latest
        dockerImage = pkgs.dockerTools.streamLayeredImage {
          name = "datapass";
          tag = "latest";
          contents = [datapass pkgs.cacert];
          config = {
            Cmd = ["${datapass}/bin/datapass"];
            Env = ["SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"];
          };
        };

        # Treefmt configuration
        treefmtEval = treefmt-nix.lib.evalModule pkgs {
          projectRootFile = "flake.nix";
          programs = {
            alejandra.enable = true; # Nix formatter
            # rustfmt handled by pre-commit hooks
            prettier.enable = true; # JSON, YAML, Markdown formatter
            taplo.enable = true; # TOML formatter
          };
        };

        # Pre-commit hooks configuration
        pre-commit-check = git-hooks.lib.${system}.run {
          src = ./.;
          hooks = {
            # Formatting
            rustfmt = {
              enable = true;
              packageOverrides = {
                cargo = rustToolchain;
                rustfmt = rustToolchain;
              };
            };
            alejandra.enable = true;
            prettier = {
              enable = true;
              excludes = ["test/.*\\.html$"];
            };
            taplo.enable = true;

            # Linting
            clippy = {
              enable = true;
              packageOverrides = {
                cargo = rustToolchain;
                clippy = rustToolchain;
              };
            };
            deadnix.enable = true;
            statix.enable = true;

            # Tests
            cargo-test = {
              enable = true;
              name = "cargo test";
              entry = "${rustToolchain}/bin/cargo test";
              files = "\\.(rs|toml)$";
              pass_filenames = false;
            };
          };
        };
      in {
        # Package outputs
        packages = {
          default = datapass;
          inherit datapass dockerImage;
        };

        # Development shell
        devShells.default = craneLib.devShell {
          packages = with pkgs; [
            # Rust tools
            rustToolchain
            cargo-watch
            cargo-edit
            cargo-audit
            cargo-outdated

            # Build dependencies
            pkg-config
            openssl

            # Formatters and linters
            treefmt
            alejandra # Nix formatter
            rustfmt
            clippy
            deadnix # Find dead Nix code
            statix # Lints and suggestions for Nix

            # Tools for formatting other files
            nodePackages.prettier
            taplo # TOML formatter

            # Cross compilation tools
            cargo-cross

            # Container tools
            skopeo

            # Useful utilities
            ripgrep
            fd
            jq
          ];

          shellHook = ''
            ${pre-commit-check.shellHook}
            echo "🦀 datapass development shell"
            echo "Available commands:"
            echo "  cargo build        - Build the project"
            echo "  cargo test         - Run tests"
            echo "  cargo run          - Run the application"
            echo "  cargo clippy       - Run linter"
            echo "  treefmt            - Format all files"
            echo "  nix flake check    - Run all checks"
            echo ""
            echo "✓ Pre-commit hooks installed"
          '';
        };

        # Formatter (run with: nix fmt)
        formatter = treefmtEval.config.build.wrapper;

        # Checks (run with: nix flake check)
        checks = {
          # Build check
          inherit datapass;

          # Pre-commit hooks check
          inherit pre-commit-check;

          # Clippy check
          datapass-clippy = craneLib.cargoClippy (commonArgs
            // {
              inherit cargoArtifacts;
              cargoClippyExtraArgs = "--all-targets -- --deny warnings";
            });

          # Documentation check
          datapass-doc = craneLib.cargoDoc (commonArgs
            // {
              inherit cargoArtifacts;
            });

          # Audit dependencies (commented out - uncomment and update sha256 to enable)
          # datapass-audit = craneLib.cargoAudit {
          #   inherit src;
          #   advisory-db = pkgs.fetchFromGitHub {
          #     owner = "rustsec";
          #     repo = "advisory-db";
          #     rev = "refs/heads/main";
          #     sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
          #   };
          # };

          # Nix-specific checks
          deadnix-check =
            pkgs.runCommand "deadnix-check" {
              nativeBuildInputs = [pkgs.deadnix];
            } ''
              deadnix --fail ${self}
              touch $out
            '';

          statix-check =
            pkgs.runCommand "statix-check" {
              nativeBuildInputs = [pkgs.statix];
            } ''
              statix check ${self}
              touch $out
            '';
        };

        # Apps (run with: nix run)
        apps.default = flake-utils.lib.mkApp {
          drv = datapass;
        };
      }
    );
}