From 11fb0d773b4df7fe8146f22d1a045e0da78e094d Mon Sep 17 00:00:00 2001 From: Deepak Mallubhotla Date: Tue, 7 Oct 2025 09:55:18 -0500 Subject: [PATCH] initial commit --- .gitattributes | 3 + .gitea/setup-secrets.sh | 73 ++++++ .gitea/workflows/nix-test.yaml | 78 ++++++ .gitea/workflows/publish.yaml | 139 +++++++++++ .gitea/workflows/python-test.yaml | 66 +++++ .gitignore | 156 ++++++++++++ .versionrc | 10 + README.md | 37 +++ flake.nix | 162 +++++++++++++ justfile | 67 ++++++ pyproject.toml | 67 ++++++ scripts/populate_cache.sh | 36 +++ scripts/populate_cache_exclude_patterns.txt | 6 + scripts/restore_cache.sh | 16 ++ src/hello_world/__init__.py | 22 ++ tests/test_me.py | 11 + treefmt.nix | 27 +++ uv.lock | 254 ++++++++++++++++++++ 18 files changed, 1230 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitea/setup-secrets.sh create mode 100644 .gitea/workflows/nix-test.yaml create mode 100644 .gitea/workflows/publish.yaml create mode 100644 .gitea/workflows/python-test.yaml create mode 100644 .gitignore create mode 100644 .versionrc create mode 100644 README.md create mode 100644 flake.nix create mode 100644 justfile create mode 100644 pyproject.toml create mode 100644 scripts/populate_cache.sh create mode 100644 scripts/populate_cache_exclude_patterns.txt create mode 100644 scripts/restore_cache.sh create mode 100644 src/hello_world/__init__.py create mode 100644 tests/test_me.py create mode 100644 treefmt.nix create mode 100644 uv.lock diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a71de1d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto + +*.py text diff=python diff --git a/.gitea/setup-secrets.sh b/.gitea/setup-secrets.sh new file mode 100644 index 0000000..df719ab --- /dev/null +++ b/.gitea/setup-secrets.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# This script helps set up the required secrets for Gitea Actions +# Run this script locally to upload secrets to your Gitea instance +# Also claude wrote this script, use it more as a reference and base for hacking than anything actually useful. + +set -e + +# Ensure token is provided +if [ -z "$GITEA_TOKEN" ]; then + echo "Error: GITEA_TOKEN environment variable must be set" + echo "Create a token at https://gitea.deepak.science/user/settings/applications" + echo "Then run: export GITEA_TOKEN=your_token" + exit 1 +fi + +# API URL from your Gitea instance +GITEA_API_URL="https://gitea.deepak.science/api/v1" +REPO_OWNER="$(git remote get-url origin | sed -E 's/.*[:/]([^/]+)\/[^/]+$/\1/')" +REPO_NAME="$(git remote get-url origin | sed -E 's/.*[:/][^/]+\/([^/.]+)(\.git)?$/\1/')" + +echo "Setting up secrets for $REPO_OWNER/$REPO_NAME" + +# Function to create/update a secret +create_secret() { + local secret_name="$1" + local secret_value="$2" + local description="$3" + + echo "Setting up secret: $secret_name - $description" + + # Create payload + local payload="{\"name\":\"$secret_name\",\"data\":\"$secret_value\"}" + + # Send to Gitea API + curl -X PUT \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d "$payload" \ + "$GITEA_API_URL/repos/$REPO_OWNER/$REPO_NAME/secrets/$secret_name" + + echo -e "\nDone!\n" +} + +# Prompt for required secrets +read -r -p "Enter SSH_GITEA_SSH_KEY (private SSH key for Git operations): " -s SSH_KEY +echo +create_secret "SSH_GITEA_SSH_KEY" "$SSH_KEY" "SSH key for Git operations in CI" + +read -r -p "Enter SSH_GITEA_KNOWN_HOSTS (content for known_hosts file): " KNOWN_HOSTS +create_secret "SSH_GITEA_KNOWN_HOSTS" "$KNOWN_HOSTS" "Known hosts for SSH connections" + +read -r -p "Enter PYPI_USERNAME: " PYPI_USER +create_secret "PYPI_USERNAME" "$PYPI_USER" "PyPI username for publishing" + +read -r -p "Enter PYPI_API_TOKEN: " -s PYPI_TOKEN +echo +create_secret "PYPI_API_TOKEN" "$PYPI_TOKEN" "PyPI API token for publishing" + +read -r -p "Enter ATTIC_ENDPOINT (URL for Attic cache): " ATTIC_ENDPOINT +create_secret "ATTIC_ENDPOINT" "$ATTIC_ENDPOINT" "Attic cache endpoint URL" + +read -r -p "Enter ATTIC_CACHE (name of Attic cache): " ATTIC_CACHE +create_secret "ATTIC_CACHE" "$ATTIC_CACHE" "Attic cache name" + +read -r -p "Enter ATTIC_TOKEN (authentication token for Attic): " -s ATTIC_TOKEN +echo +create_secret "ATTIC_TOKEN" "$ATTIC_TOKEN" "Attic authentication token" + +# Create GITEA_TOKEN secret for self-service PR creation +create_secret "GITEA_TOKEN" "$GITEA_TOKEN" "Gitea API token for automation" + +echo "All secrets have been set up! Your Gitea Actions workflows should now work properly." +echo "Make sure to give execution permission to this script with: chmod +x .gitea/setup-secrets.sh" diff --git a/.gitea/workflows/nix-test.yaml b/.gitea/workflows/nix-test.yaml new file mode 100644 index 0000000..37e1e84 --- /dev/null +++ b/.gitea/workflows/nix-test.yaml @@ -0,0 +1,78 @@ +name: Nix Tests +run-name: ${{ gitea.actor }} running Nix tests +on: + push: + branches: ["*"] + pull_request: + branches: [master] + workflow_dispatch: +jobs: + nix-test: + # Using matrix to run on different runners if needed + strategy: + fail-fast: true + matrix: + # You can adjust to run on different runners or environments + # os: [ubuntu-latest, nix-runner] + os: [nix-runner] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + # SSH keys setup is important for accessing private repositories + # Adjust or remove this section if not needed + # - name: Install SSH keys + # uses: shimataro/ssh-key-action@d4fffb50872869abe2d9a9098a6d9c5aa7d16be4 + # with: + # key: ${{ secrets.SSH_GITEA_SSH_KEY }} + # name: gitea_action + # known_hosts: ${{ secrets.SSH_GITEA_KNOWN_HOSTS }} + # - name: Agent SSH keys + # uses: webfactory/ssh-agent@v0.9.0 + # with: + # ssh-private-key: ${{ secrets.SSH_GITEA_SSH_KEY }} + # Cache nix https://github.com/cachix/install-nix-action/issues/56#issuecomment-1240991760 + - name: "Cache Nix store" + uses: actions/cache@v4 + id: nix-cache + with: + path: /tmp/nixcache + key: nix-d-${{ runner.os }}-HELLOCHANGEME-${{ hashFiles('**/pyproject.toml', '**/*.nix', '**/uv.lock', '**/scripts/*.sh', '**/flake.lock') }} + restore-keys: | + nix-d-${{ runner.os }}-HELLOCHANGEME- + nix-d-${{ runner.os }} + nix-d + # Installing Nix - not necessary if using nix-runner but included for completeness + # - name: Install Nix + # uses: cachix/install-nix-action@v31 + - name: Setup Attic Cache + uses: ryanccn/attic-action@3354ae812cb672e1381be4c7914204c44db53866 + with: + endpoint: ${{ secrets.ATTIC_ENDPOINT }} + cache: ${{ secrets.ATTIC_CACHE }} + token: ${{ secrets.ATTIC_TOKEN }} + - name: "Import Nix store cache" + continue-on-error: true + # if: "steps.nix-cache.outputs.cache-hit == 'true'" + run: bash scripts/restore_cache.sh + # Build and check the Nix flake + - name: Build and Check Nix Flake + run: nix flake check + # Artifacts collection + - name: List files after test + run: ls + - name: Archive test results + uses: christopherhx/gitea-upload-artifact@v4 + if: always() # Always upload test results, even if tests fail + with: + name: test-results-nix + path: | + pytest.xml + coverage.xml + htmlcov/ + retention-days: 7 + - name: "Export Nix store cache" + # if: "steps.nix-cache.outputs.cache-hit != 'true'" + run: bash scripts/populate_cache.sh diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml new file mode 100644 index 0000000..8b1bcea --- /dev/null +++ b/.gitea/workflows/publish.yaml @@ -0,0 +1,139 @@ +name: Build and Publish +on: + push: + # Only trigger on tags with version format + tags: + - '*.*.*' + # Allow manual triggering for testing + workflow_dispatch: +jobs: + # Use Python build first, as fallback + build-python: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install build tools + run: | + python -m pip install --upgrade pip + pip install build twine + - name: Build package + run: | + python -m build + - name: Store Python build + uses: christopherhx/gitea-upload-artifact@v4 + with: + name: python-package + path: | + dist/*.tar.gz + dist/*.whl + retention-days: 7 + build-uv: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install the project + run: uv sync --all-extras --dev + - name: Build package + run: | + uv build + - name: Store Python build + uses: christopherhx/gitea-upload-artifact@v4 + with: + name: uv-package + path: | + dist/*.tar.gz + dist/*.whl + retention-days: 7 + # Use Nix build as primary method + # build-nix: + # runs-on: nix-runner + # steps: + # - name: Checkout repository + # uses: actions/checkout@v4 + # with: + # fetch-depth: 0 + # - name: Setup Attic Cache + # uses: ryanccn/attic-action@3354ae812cb672e1381be4c7914204c44db53866 + # with: + # endpoint: ${{ secrets.ATTIC_ENDPOINT }} + # cache: ${{ secrets.ATTIC_CACHE }} + # token: ${{ secrets.ATTIC_TOKEN }} + # # Build the package using Nix + # - name: Build with Nix + # run: | + # # Build Python package with Nix + # # Adjust this to match your flake output for the Python package + # nix build .#pythonPackage + # - name: Copy built package to dist + # run: | + # mkdir -p dist + # cp -r result/* dist/ || echo "Failed to copy result to dist - check paths" + # - name: Store Nix build + # uses: christopherhx/gitea-upload-artifact@v4 + # with: + # name: nix-package + # path: dist/ + # retention-days: 7 + # Publish to PyPI + publish-pypi: + needs: [build-python, build-uv] + runs-on: ubuntu-latest + environment: + name: pypi + # Only publish on tag push, not on manual workflow dispatch + if: startsWith(github.ref, 'refs/tags/') + steps: + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + - name: Download Uv build + uses: christopherhx/gitea-download-artifact@v4 + with: + name: uv-package + path: dist-uv + - name: Download Python build (fallback) + uses: christopherhx/gitea-download-artifact@v4 + with: + name: python-package + path: dist-python + - name: Setup distribution directory + run: | + mkdir -p dist + # Prefer Nix build results, fall back to Python build + if [ -n "$(ls -A dist-uv 2>/dev/null)" ]; then + echo "Using uv build artifacts" + cp -r dist-uv/* dist/ + elif [ -n "$(ls -A dist-nix 2>/dev/null)" ]; then + echo "Using Nix build artifacts" + cp -r dist-nix/* dist/ + else + echo "Using Python build artifacts" + cp -r dist-python/* dist/ + fi + - name: Print distribution directory + run: ls -la dist + - name: Publish to PyPI + run: uv publish + env: + UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + # Use TestPyPI for non-production releases + # repository-url: https://test.pypi.org/legacy/ diff --git a/.gitea/workflows/python-test.yaml b/.gitea/workflows/python-test.yaml new file mode 100644 index 0000000..10f0971 --- /dev/null +++ b/.gitea/workflows/python-test.yaml @@ -0,0 +1,66 @@ +name: Python Tests +run-name: ${{ gitea.actor }} running Python tests +on: + push: + branches: ["*"] + pull_request: + branches: [master] + workflow_dispatch: +jobs: + python-test: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + - name: "Set up Python" + uses: actions/setup-python@v5 + with: + python-version-file: "pyproject.toml" + - name: Install dependencies + run: | + uv sync --all-extras --dev + # This check ensures formatting is correct without modifying files + - name: Check formatting + run: | + uv run ruff format --check src tests + - name: Run linting + run: | + uv run ruff check src tests + - name: Run type checking + run: | + uv run mypy src + - name: Run tests + run: | + uv run pytest + # Artifacts collection + - name: Archive test results + uses: christopherhx/gitea-upload-artifact@v4 + if: always() # Always upload test results, even if tests fail + with: + name: test-results + path: | + pytest.xml + coverage.xml + htmlcov/ + retention-days: 7 + # This lets you see the coverage report in the Gitea UI + - name: Comment coverage + # Only run on PRs + if: github.event_name == 'pull_request' + run: | + COVERAGE=$(python -c "import xml.etree.ElementTree as ET; tree = ET.parse('coverage.xml'); root = tree.getroot(); print(float(root.attrib['line-rate']) * 100)") + + echo "Current coverage: ${COVERAGE}%" + + # Post comment to PR using Gitea API + curl -X POST \ + -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + -H "Content-Type: application/json" \ + -d "{\"body\": \"📊 **Test Coverage**: ${COVERAGE}%\"}" \ + ${{ gitea.api_url }}/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a399bad --- /dev/null +++ b/.gitignore @@ -0,0 +1,156 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +pytest.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# direnv +.envrc +.direnv + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# *.csv + +local_scripts/ + +.vscode + +logs/ +out/ +*.xlsx + +# nix +result diff --git a/.versionrc b/.versionrc new file mode 100644 index 0000000..0e99104 --- /dev/null +++ b/.versionrc @@ -0,0 +1,10 @@ +{ + "bumpFiles": [ + { + "filename": "pyproject.toml", + "type": "python" + } + ], + "sign": true, + "tag-prefix": "" +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..e9e192f --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# hello-world - The default project (change me). + +[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-green.svg?style=flat-square)](https://conventionalcommits.org) +[![PyPI](https://img.shields.io/pypi/v/{{ NAME }}?style=flat-square)](https://pypi.org/project/{{ NAME }}/) +![Maintenance](https://img.shields.io/maintenance/yes/2025?style=flat-square) + +Default to using justfile as local script holder +Testing out using uv +Using poetry for management, etc. +In nix, nix fmt does formatting for everything. + +# Getting started + +1. You may need to initialise a git repository. + * `git init`, `git add .`, `git commit -m "initial commit"` + +2. Double check if you need to update nixpkgs, update python version etc. + * in nix, some version of `nix flake update`, changing python version in flake.nix etc. + +3. The placeholder names used throughout are not all consistent at all. +Sorry. +Iteratively bug slaying should get you there. + +4. Get a dev shell to play around. +Probably allowing direnv will be the easiest startup. +Remember that it won't work until you fix all the placeholder names and make an initial commit. +So + +5. Do that. + +## dev + +Build with `just`, preferred over `do.sh` I think. + +## CLI + +Details of how to use this cli in this project diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..8e2ad4d --- /dev/null +++ b/flake.nix @@ -0,0 +1,162 @@ +{ + description = "Application packaged using poetry2nix"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs"; + + inputs.treefmt-nix.url = "github:numtide/treefmt-nix"; + + inputs.pyproject-nix.url = "github:pyproject-nix/pyproject.nix"; + inputs.pyproject-nix.inputs.nixpkgs.follows = "nixpkgs"; + inputs.uv2nix = { + url = "github:pyproject-nix/uv2nix"; + inputs.pyproject-nix.follows = "pyproject-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + inputs.pyproject-build-systems = { + url = "github:pyproject-nix/build-system-pkgs"; + inputs.pyproject-nix.follows = "pyproject-nix"; + inputs.uv2nix.follows = "uv2nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = + { + self, + nixpkgs, + treefmt-nix, + uv2nix, + pyproject-nix, + pyproject-build-systems, + }: + let + # inherit (nixpkgs) lib; + # pkgs = nixpkgs.legacyPackages.${system}; + supportedSystems = [ "x86_64-linux" ]; + pkgsFor = + system: + nixpkgs.legacyPackages.${system}.extend ( + # blank but overlays can go here + nixpkgs.lib.composeManyExtensions ([ ]) + ); + eachSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f (pkgsFor system)); + + treefmtEval = eachSystem (pkgs: treefmt-nix.lib.evalModule pkgs ./treefmt.nix); + workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; + overlay = workspace.mkPyprojectOverlay { sourcePreference = "wheel"; }; + + pythonSet = ( + pkgs: + let + python = pkgs.python312; + pyprojectOverrides = final: prev: { + jaconv = prev.jaconv.overrideAttrs (old: { + + nativeBuildInputs = + old.nativeBuildInputs or [ ] + ++ (final.resolveBuildSystem { + setuptools-scm = [ ]; + setuptools = [ ]; + }); + }); + }; + + in + (pkgs.callPackage pyproject-nix.build.packages { inherit python; }).overrideScope ( + nixpkgs.lib.composeManyExtensions [ + pyproject-build-systems.overlays.default + overlay + pyprojectOverrides + ] + ) + ); + + in + { + # formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixpkgs-fmt); + formatter = eachSystem (pkgs: treefmtEval.${pkgs.system}.config.build.wrapper); + + # for `nix flake check` + checks = eachSystem (pkgs: { + formatting = treefmtEval.${pkgs.system}.config.build.check self; + }); + + packages = eachSystem (pkgs: { + + default = (pythonSet pkgs).mkVirtualEnv "hello-world-env" workspace.deps.default; + + }); + devShells = eachSystem ( + pkgs: + let + + inherit (pkgs) lib; + thisPythonSet = pythonSet pkgs; + editableOverlay = workspace.mkEditablePyprojectOverlay { root = "$REPO_ROOT"; }; + # Override previous set with our overrideable overlay. + editablePythonSet = thisPythonSet.overrideScope ( + lib.composeManyExtensions [ + editableOverlay + + # Apply fixups for building an editable package of your workspace packages + (final: prev: { + # Change some stuff here for your new project! + hello-world = prev.hello-world.overrideAttrs (old: { + # It's a good idea to filter the sources going into an editable build + # so the editable package doesn't have to be rebuilt on every change. + # I stole this from pyproject-nix but still don't know what this does + src = lib.fileset.toSource { + root = old.src; + fileset = lib.fileset.unions [ + (old.src + "/pyproject.toml") + (old.src + "/README.md") + (old.src + "/src/hello_world/__init__.py") + ]; + }; + + # Hatchling (our build system) has a dependency on the `editables` package when building editables. + # + # In normal Python flows this dependency is dynamically handled, and doesn't need to be explicitly declared. + # This behaviour is documented in PEP-660. + # + # With Nix the dependency needs to be explicitly declared. + nativeBuildInputs = old.nativeBuildInputs ++ final.resolveBuildSystem { editables = [ ]; }; + }); + + }) + ] + ); + virtualenv = editablePythonSet.mkVirtualEnv "hello-world-dev-env" workspace.deps.all; + + in + { + default = pkgs.mkShell { + # inputsFrom = [ self.packages.${system}.myappApp ]; + packages = [ + virtualenv + pkgs.uv + pkgs.pyright + pkgs.nodejs + pkgs.just + ]; + env = { + DO_NIX_CUSTOM = "1"; + # Force uv to use Python interpreter from venv + UV_PYTHON = "${virtualenv}/bin/python"; + + # Prevent uv from downloading managed Python's + UV_PYTHON_DOWNLOADS = "never"; + }; + shellHook = '' + # Undo dependency propagation by nixpkgs. + unset PYTHONPATH + + # Get repository root using git. This is expanded at runtime by the editable `.pth` machinery. + export REPO_ROOT=$(git rev-parse --show-toplevel) + ''; + }; + } + ); + }; + +} diff --git a/justfile b/justfile new file mode 100644 index 0000000..1fff8f9 --- /dev/null +++ b/justfile @@ -0,0 +1,67 @@ +# List just commands by default +default: + just --list + +# builds the python module using poetry +build: + echo "building..." + # poetry build + +# print a message displaying whether nix is being used +checknix: + #!/usr/bin/env bash + set -euxo pipefail + if [[ "${DO_NIX_CUSTOM:=0}" -eq 1 ]]; then + echo "In an interactive nix env." + else + echo "Using uv as runner, no nix detected." + fi + +# update all test snapshots, use if snapshots are out of date +update-snapshots: + #!/usr/bin/env bash + set -euxo pipefail + uv run pytest --snapshot-update + +# run all tests +test: + #!/usr/bin/env bash + set -euxo pipefail + + # would love test: fmt to make sure formatting happens but in WSL formatting is slow... + # poor filesystem access performance + + echo "testing..." + uv run ruff check src tests + uv run mypy src + uv run pytest + +check: + #!/usr/bin/env bash + set -euxo pipefail + + nix flake check + +# format code +fmt: + #!/usr/bin/env bash + set -euxo pipefail + + # uv run ruff --format + nix fmt + +# release the app, checking that our working tree is clean and ready for release +release: + ./scripts/release.sh + +htmlcov: + poetry run pytest --cov-report=html + +zsh_completions: + #!/usr/bin/env bash + set -euxo pipefail + if [[ "${DO_NIX_CUSTOM:=0}" -eq 1 ]]; then + eval "$(_HELLO_WORLD_COMPLETE=zsh_source hello_world)" + else + echo "Nope only nix." + fi diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..08553c2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,67 @@ +[project] +name = "hello-world" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ +#"urllib3>=2.2.3", +] + +[project.scripts] +hello = "hello_world:main" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[dependency-groups] +dev = [ + "flake8>=7.1.2", + "mypy>=1.15.0", + "pytest>=8.3.5", + "pytest-cov>=6.0.0", + "ruff>=0.6.7", + "syrupy>=4.9.0", +] + +[tool.ruff.format] +indent-style = "tab" + +[tool.hatch.build.targets.wheel] +sources = ["src"] + +# [tool.poetry.group.dev.dependencies] +# mypy = "*" +# python-semantic-release = "*" + +[tool.pytest.ini_options] +testpaths = ["tests"] +# Uncomment to care about coverage +addopts = "--junitxml pytest.xml --cov src --cov-report=xml:coverage.xml --cov-fail-under=50 --cov-report=html" +junit_family = "xunit1" +log_format = "%(asctime)s | %(levelname)s | %(pathname)s:%(lineno)d | %(message)s" +log_level = "WARNING" + +# [tool.mypy] +# If you need this +# plugins = "numpy.typing.mypy_plugin" + +# [[tool.mypy.overrides]] +# module = [ +# "scipy", +# "scipy.optimize", +# "scipy.stats", +# "scipy.fft", +# ] +# ignore_missing_imports = true + +# [tool.semantic_release] +# branch = "master" +# version_variable = [ +# "src/__init__.py:__version__", +# "pyproject.toml:version" +# ] +# upload_to_pypi = false +# upload_to_release = false +# build_command = "pip install poetry && poetry build"j diff --git a/scripts/populate_cache.sh b/scripts/populate_cache.sh new file mode 100644 index 0000000..2227dda --- /dev/null +++ b/scripts/populate_cache.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +CACHE_PATH=${CACHE_PATH:-"/tmp/nixcache"} + +banner() { + echo "========================================================" + echo " $*" + echo "========================================================" +} + +banner "List what we start with" + +nix-store --query --requisites --include-outputs "$(nix eval .\#devShells.x86_64-linux.default.drvPath --raw)" >dependencies.txt +nix-store --query --requisites --include-outputs "$(nix eval .\#packages.x86_64-linux.default.drvPath --raw)" >>dependencies.txt +# nix-store --query --requisites --include-outputs "$(nix eval .\#checks.x86_64-linux.formatting.drvPath --raw)" >>dependencies.txt +# nix-store --query --requisites --include-outputs "$(nix eval .\#checks.x86_64-linux.test-check.drvPath --raw)" >>dependencies.txt +nix-store --query --requisites --include-outputs "$(nix eval .\#formatter.x86_64-linux.drvPath --raw)" >>dependencies.txt + +sort -o dependencies.txt -u dependencies.txt + +banner "list obtained paths to cache" + +wc -l dependencies.txt + +banner "filter out our matches" + +echo "Using filter" +cat scripts/populate_cache_exclude_patterns.txt + +grep -vf scripts/populate_cache_exclude_patterns.txt dependencies.txt >filtered_dependencies.txt + +echo "Count our filtered" +wc -l filtered_dependencies.txt + +xargs