# Repo Rules

- DO NOT git push --force
- Do not manually edit generated source files such as `_sources/generated.nix` or `_sources/generated.json`. When source metadata needs to be refreshed, run `nix run nixpkgs#nvfetcher` from the repo root and let it update generated files.
- Do not manually edit generated Gradle MITM lockfiles such as `*_deps.json` / `immich_deps.json`; regenerate them only via the package's `mitmCache.updateScript`. If the `updateScript` itself fails (e.g. composite build env issues, version mismatches, Gradle 8/9 resolution differences), see [docs/gradle-deps-troubleshooting.md](docs/gradle-deps-troubleshooting.md) for a diagnostic checklist — only consult this when the normal `updateScript` approach has failed.
- Use `nurl --fetcher=fetchpatch`, or run `nix run nixpkgs#nurl -- --fetcher=fetchpatch <url to patch>`, to get a `fetchpatch` expression for patch URLs.
- Never use `sed -i` to patch source files in Nix derivations. Use `substituteInPlace --replace-fail` for single-line substitutions. For multi-line or structural changes, generate a proper patch with diff/git diff against the real upstream source file; never write patch hunks by hand.
- Never use `perl -i` / `perl -pe` or python source rewriting in Nix derivations; use `substituteInPlace --replace-fail` or a proper diff/git diff patch instead.
- Follow patterns of exisiting code, learn from exisiting working code and nixpkgs
- Make sure `nix build` actually can build before declaring completing a task!
- Remember to `git add` when nix complaints about path does not exist!
- Remember no network in nix build environemnt expect for fixed output derviation!!
- Always set hash to fakeHash or empty before needing to get new hash like changed fetch options updated tag rev!
- for `''` in nix, prefixing common spaces will be removed. please format nix files corectly that is bash heredoc within double quotes block in nix can have similar indentation as the rest of the file. if unsure run nixfmt on the file and check what did nixfmt do!
- update mitm: `$(nix build .\#apk_tailscale.mitmCache.updateScript --no-link --print-out-paths)` note on nix: always use ./ instead of double quote string for data path! otherwise the outPath in mitmCache update script is not what we want. use `mitmCache = gradle.fetchDeps { pkg = finalAttrs.finalPackage; data = ./tailscale_deps.json;`; never use `data = "tailscale_deps.json";` It is common to see cleanup errors. Cleanup errors should not affect the main functionality of the mitmCache update script. Maybe need to put multiple tasks in gradleUpdateTask, seperated by space, if needed, when a specific task failed to build due to dependencies not in mitmCache. when write gradle.fetchDeps, always write pkg explicitly!
- fetchFromGitHub and fetching from git in nix: prefer tag over rev, use tag = "tag name" when fetching tag!
- DON"T EVER find grep or anything SEARCH ON EVERY FILES ON WHOLE nix store!!!! nix store is big and that takes forever.
- When working on patches. you try build for example gos.husky.config.source.dirs."path here".src to see if patch apply.
- we are using `buildGradlePackage` gradle2nix v2 <https://github.com/tadfisher/gradle2nix/pull/62> We use gradle2nix v2 or nixpkgs mitm gradle.fetchDeps way; pick the one that fits the most. gradle2nix v2 only officially support gradle 8.0 and later. Use gradle2nix instead of that mitm gradle.fetchDeps thing whenever possible. when using buildGradlePackage that by default `overrides = overrides-fromsrc;` is applied so that we use those libraries built from source code version and the binray versions are being overrided. set an explicit overrides when needed to. optionally use `overrides = overrides-fromsrc-updated` to force update dependencies to newer versions. gradle.lock generation command example: `nix run github:tadfisher/gradle2nix/v2  -- --gradle-wrapper=8.2` (run on the dir of gradle project, you might want to omit gradle-wrapper option or give it different option) please pin gradle to an exact version. gradle.lock can change even if gradle version is only moved by patch version. Editing gradle.lock is only acceptable for pinned project versions for limited reasons. When a project has frequently updates, gradle.lock is expected to be generated by gradle2nix only and not edited by hand. Under extreme conditions it might be faster to write gradle.lock by hand and copy sections of other gradle.lock around when gradle2nix lock generation is not working. see gradle_8_11_20240809/refresh-hashes.sh to refresh hash of hand written gradle.lock with correct url but incorrect hash. For android apps go to a git clone of app source and do for example `nix develop /path/to/repo#apk_glimpse -c nix run github:tadfisher/gradle2nix/v2`. For some missing dependencies cases use `mergeLock`
- When fetching sources we prefer fetchFromGithub or fetchgit over a tarball provided by some party like tarball uploaded on github release. Do you remember the xz incident? it is safer to fetch from git or github.
- app/by-name-apk are exported with `apk_` prefix so appstore becomes `nix build .#apk_appstore`
- don't use callPackage and pkgs in a package's first arguments list which usually contan dependencies of that package. only allowed when not easy to refactor without pkgs and callPackage in argument list
- we prefer mvn2nix & mkMavenPackageWithLock or buildMavenRepositoryFromLockFile over maven.buildMavenPackage
- android gradle plugin AGP 9.x seems to have silent problem with old build-tools and old aapt&aapt2. When a result apk has no AndroidManifest.xml with AGP 9.x, check and make sure android sdk is the needed version. maybe need newer version. Specifically, build-tools-35-0-0 seems to have problem with AGP 9.x, causing corrupted apk result. build-tools-36-0-0 is working fine. Need to completly remove build-tools-35-0-0 from android sdk.
- don't fetch dependencies jars manually with fetchurl. even if the list is manual, use `buildMavenRepository` with mvn2nix format, or `gradle.fetchDeps` with nixpkgs gradle format, or `buildMavenRepo` with gradle2nix v2 format. The reason is that they support overrides-fromsrc and use overrides-fromsrc by default in our repository. use `maven_3_9_14/refresh-hashes.sh` to refresh mvn2nix-lock.json format that might be written by hand with correct url but incorrect hash. use `gradle_8_11_20240809/refresh-hashes.sh` to refresh gradle2nix v2 gradle.lock format that might be written by hand with correct url but incorrect hash. there are some methods for maven based projects if normal methods failed. read maven_3_9_14/README.md and maven_3_3_9/README.md
- When error: infinite recursion encountered happens, --show-trace, see if it is the case that a package defined unnecessary dependency causing cyclic dependency. if so just remove that dependency.
- old code is having logic for example like `if stdenv.isDarwin then "${jdk25_headless}" else "${jdk25_headless}/lib/openjdk"`. please use .passthru.home like `jdk25_headless.passthru.home` for example for new code and optionally update old code to use .passthru.home
- When need a home, use writableTmpDirAsHomeHook with `export GRADLE_USER_HOME="$HOME/.gradle"` `"-Dmaven.repo.local=$HOME/.m2/repository"` or similar.
- Prefer mv in installPhase over cp because it is faster
- JDK 11 can be unstable in some Gradle source builds (daemon crash/disappear). If it fails with that symptom, retry once before changing package logic.
- When asked for "apk update" generally, do not check or update packages managed by `nvfetcher`. Only check packages with custom update scripts (`updateScript`) or git-based ones not in `nvfetcher.toml`. You can use the `check_updates.py` script for this.
- When asked to check updates, just check and list them using the `check_updates.py` script. Do not automatically update them unless explicitly told to.
- The Android SDK 37 naming scheme in `android-nixpkgs` uses `platforms-android-37-0` (instead of `platforms-android-37`), and `build-tools-37-0-0`. Keep this in mind when specifying SDK 37 dependencies.
- Use [docs/temporary-scripts.md](docs/temporary-scripts.md) to store and document temporary scripts used to solve problems (such as bulk fetching hashes). These should only be used when normal update scripts have failed.
