├── VERSION ├── docs ├── artwork ├── README.md ├── troubleshoot.md ├── SUMMARY.md ├── run-tests.md ├── install.md ├── custom-upstream.md ├── install └── new-app.md ├── examples ├── templates │ └── frappe │ │ ├── config │ │ ├── logs │ │ ├── pyenv │ │ ├── sites │ │ ├── apps │ │ ├── _pins │ │ │ ├── .gitkeep │ │ │ ├── versions.json │ │ │ ├── generated.nix │ │ │ └── config.toml │ │ ├── _pins.nix │ │ └── pkgs.nix │ │ ├── archived │ │ ├── tools │ │ ├── tasks.nix │ │ └── shells.nix │ │ ├── .envrc │ │ ├── .gitignore │ │ └── flake.nix └── templates.nix ├── apps ├── sources │ ├── versions.json │ ├── drive.nix │ ├── crm.nix │ ├── wiki.nix │ ├── bench.nix │ ├── hrms.nix │ ├── builder.nix │ ├── webshop.nix │ ├── insights.nix │ ├── payments.nix │ ├── print-designer.nix │ ├── gameplan.nix │ ├── ecommerce-integrations.nix │ ├── raven.nix │ ├── frappe-website-generator.patch │ ├── erpnext.nix │ ├── frappe.nix │ ├── frappe-uds-current-user-v15.patch │ ├── frappe-uds-current-user-develop.patch │ └── config.toml ├── sources.md └── sources.nix ├── artwork ├── logo.png └── logo.svg ├── src ├── overlays │ ├── libs │ │ ├── default.nix │ │ └── redi-search │ │ │ ├── rl-test.nix │ │ │ ├── cmake-fixes.patch │ │ │ └── default.nix │ ├── tools │ │ ├── analyze-prs.nix │ │ ├── start-mariadb-for-frappe.nix │ │ ├── frx.nix │ │ ├── fsjd.nix │ │ ├── default.nix │ │ ├── bench.nix │ │ ├── mkAssets.nix │ │ ├── nvchecker.nix │ │ ├── mkSiteAssets.nix │ │ ├── apps.nix │ │ └── analyze-prs.py │ ├── default.nix │ ├── python │ │ ├── email-reply-parser.nix │ │ ├── paytmchecksum.nix │ │ ├── linkpreview.nix │ │ ├── sql_metadata.nix │ │ ├── barcodenumber.nix │ │ ├── premailer.nix │ │ ├── plaid-python.nix │ │ ├── json-source-map.nix │ │ ├── razorpay.nix │ │ ├── pyactiveresource.nix │ │ ├── uuid-utils.nix │ │ ├── rauth.nix │ │ ├── shopify-python-api.nix │ │ ├── default.nix │ │ ├── traceback-with-variables │ │ │ ├── default.nix │ │ │ └── 01-fix-test-ouput.patch │ │ └── rembg.nix │ ├── frappe │ │ ├── wiki │ │ │ └── default.nix │ │ ├── webshop.nix │ │ ├── raven │ │ │ └── default.nix │ │ ├── hrms-0001-build-socket-port-is-reverse-proxied.patch │ │ ├── default.nix │ │ ├── hrms.nix │ │ ├── builder.nix │ │ ├── insights-0001-build-socket-port-is-reverse-proxied.patch │ │ ├── print-designer.nix │ │ ├── ecommerce-integrations.nix │ │ ├── crm.nix │ │ ├── gameplan │ │ │ ├── 0000-build-socket-port-is-reverse-proxied.patch │ │ │ └── default.nix │ │ ├── payments.nix │ │ ├── insights.nix │ │ ├── crm-0001-build-socket-port-is-reverse-proxied.patch │ │ ├── erpnext.nix │ │ ├── drive │ │ │ └── default.nix │ │ └── frappe.nix │ └── Readme.md ├── oci-images.nix ├── pkgs.nix ├── oci.nix ├── nixos.nix ├── oci │ ├── testrig.nix │ └── main.nix ├── nixos │ ├── test-ca.pem │ ├── test-cert.pem │ ├── test-key.pem │ ├── testrig.nix │ ├── nginx.nix │ └── main.nix ├── Readme.md ├── vms.nix ├── jobs.nix └── config.nix ├── book.toml ├── .envrc ├── .gitignore ├── std ├── frapper.nix └── nvchecker.nix ├── local ├── Readme.md ├── shells.nix └── config.nix ├── .github └── workflows │ ├── std.yml │ ├── gh-pages.yaml │ └── weekly.yml ├── SCOPE.md ├── README.md ├── flake.nix └── tests ├── nixos-tests.nix ├── arion-compose.nix └── nixos-tests.md /VERSION: -------------------------------------------------------------------------------- 1 | 0.0.1 2 | -------------------------------------------------------------------------------- /docs/artwork: -------------------------------------------------------------------------------- 1 | ../artwork -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /examples/templates/frappe/config: -------------------------------------------------------------------------------- 1 | .run -------------------------------------------------------------------------------- /examples/templates/frappe/logs: -------------------------------------------------------------------------------- 1 | .data/logs -------------------------------------------------------------------------------- /examples/templates/frappe/pyenv: -------------------------------------------------------------------------------- 1 | .data/pyenv -------------------------------------------------------------------------------- /examples/templates/frappe/sites: -------------------------------------------------------------------------------- 1 | .data/sites -------------------------------------------------------------------------------- /examples/templates/frappe/apps/_pins/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/templates/frappe/archived: -------------------------------------------------------------------------------- 1 | .data/archived -------------------------------------------------------------------------------- /examples/templates/frappe/apps/_pins/versions.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /examples/templates/frappe/apps/_pins/generated.nix: -------------------------------------------------------------------------------- 1 | {...}: {} 2 | -------------------------------------------------------------------------------- /examples/templates/frappe/tools/tasks.nix: -------------------------------------------------------------------------------- 1 | inputs.frappix.src.jobs 2 | -------------------------------------------------------------------------------- /apps/sources/versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "data": {} 4 | } 5 | -------------------------------------------------------------------------------- /artwork/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blaggacao/frappix/HEAD/artwork/logo.png -------------------------------------------------------------------------------- /docs/troubleshoot.md: -------------------------------------------------------------------------------- 1 | # Troubleshoot 2 | 3 | ## Redis Services 4 | 5 | ##### `Failed to configure LOCALE for invalid locale name` 6 | 7 | ###### `export LANG=` 8 | -------------------------------------------------------------------------------- /examples/templates/frappe/apps/_pins/config.toml: -------------------------------------------------------------------------------- 1 | # run nvchecker -c config.toml 2 | [__config__] 3 | oldver = "versions.json" 4 | newver = "versions.json" 5 | nix-expr-folder = "." 6 | -------------------------------------------------------------------------------- /src/overlays/libs/default.nix: -------------------------------------------------------------------------------- 1 | inputs: final: prev: { 2 | # soft dependency on webshop 3 | # hard dependency on gameplan 4 | redi-search = final.callPackage ./redi-search {}; 5 | } 6 | -------------------------------------------------------------------------------- /examples/templates.nix: -------------------------------------------------------------------------------- 1 | { 2 | frappe = rec { 3 | path = ./templates/frappe; 4 | description = "Get started with a minimal Frappe-only frappix template"; 5 | meta = {inherit description;}; 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | language = "en" 3 | multilingual = false 4 | src = "docs" 5 | title = "Frappix Documentation" 6 | 7 | [build] 8 | build-dir = "docs/build" 9 | 10 | [output.html] 11 | 12 | [output.linkcheck] 13 | 14 | [preprocessor] 15 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # shellcheck disable=SC1090 4 | . "$(fetchurl "https://raw.githubusercontent.com/paisano-nix/direnv/main/lib" "sha256-IgQhKK7UHL1AfCUntJO2KCaIDJQotRnK2qC4Daxk+wI=")" 5 | 6 | use envreload //local/shells/default //local/config 7 | 8 | -------------------------------------------------------------------------------- /examples/templates/frappe/.envrc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # shellcheck disable=SC1090 4 | . "$(fetchurl "https://raw.githubusercontent.com/paisano-nix/direnv/main/lib" "sha256-IgQhKK7UHL1AfCUntJO2KCaIDJQotRnK2qC4Daxk+wI=")" 5 | 6 | use envreload //tools/shells/default //tools/config 7 | 8 | -------------------------------------------------------------------------------- /docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | [Introduction](README.md) 2 | 3 | # Getting Started 4 | 5 | - [Install](./install.md) 6 | - [New app](./new-app.md) 7 | - [Custom upstream](./custom-upstream.md) 8 | - [Run tests](./run-tests.md) 9 | - [Troubleshoot](./troubleshoot.md) 10 | 11 | # Avalable Templates 12 | 13 | # Contributions to Frappix 14 | -------------------------------------------------------------------------------- /src/oci-images.nix: -------------------------------------------------------------------------------- 1 | let 2 | inherit (inputs.nixpkgs) lib; 3 | inherit (cell) pkgs oci; 4 | 5 | evaled = lib.evalModules { 6 | modules = [ 7 | {_module.args = {inherit pkgs;};} 8 | oci.frappix 9 | oci.testrig 10 | ]; 11 | }; 12 | in { 13 | frappix-base = evaled.config.oci.frappix.image; 14 | } 15 | -------------------------------------------------------------------------------- /examples/templates/frappe/.gitignore: -------------------------------------------------------------------------------- 1 | # local sources except pinning instrumentation 2 | /apps/* 3 | !/apps/_pins/ 4 | !/apps/*.nix 5 | 6 | # prj spec 7 | /.bin 8 | /.cache 9 | /.config 10 | /.data 11 | /.run 12 | 13 | # nix 14 | result 15 | 16 | # vms 17 | *.qcow2 18 | 19 | # nixago: ignore-linked-files 20 | /process-compose.yaml 21 | -------------------------------------------------------------------------------- /src/overlays/tools/analyze-prs.nix: -------------------------------------------------------------------------------- 1 | { 2 | writers, 3 | python3Packages, 4 | }: 5 | (writers.writePython3Bin "analyze-prs.py" { 6 | flakeIgnore = ["E501"]; 7 | libraries = with python3Packages; [ 8 | requests 9 | tabulate 10 | ]; 11 | } 12 | ./analyze-prs.py) 13 | // {meta.description = "Analyze PRs against HEAD";} 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # nix 2 | result 3 | .nixos-test-history 4 | 5 | # nixago: ignore-linked-files 6 | /lefthook.yml 7 | /.editorconfig 8 | /.conform.yaml 9 | /treefmt.toml 10 | # nixago-auto-created: mdbook-build-folder 11 | docs/build/** 12 | 13 | # prj spec 14 | /.config 15 | /.cache 16 | /.data 17 | /.run 18 | /.bin 19 | 20 | # template development 21 | /workbench 22 | .aider* 23 | -------------------------------------------------------------------------------- /src/pkgs.nix: -------------------------------------------------------------------------------- 1 | let 2 | pkgs = import inputs.nixpkgs.path { 3 | # wkhtmltopdf 4 | config.permittedInsecurePackages = ["openssl-1.1.1w"]; 5 | config.allowUnfree = true; 6 | 7 | system = inputs.nixpkgs.system; 8 | 9 | overlays = [ 10 | cell.overlays.libs 11 | cell.overlays.tools 12 | cell.overlays.python 13 | cell.overlays.frappe 14 | ]; 15 | }; 16 | in 17 | pkgs 18 | -------------------------------------------------------------------------------- /std/frapper.nix: -------------------------------------------------------------------------------- 1 | {inputs}: 2 | /* 3 | Use the Frapper Blocktype for targets that you want to 4 | make accessible with a 'run' action on the TUI. 5 | */ 6 | let 7 | inherit (inputs.std) actions; 8 | in 9 | name: { 10 | __functor = _: self: selectors: self // selectors; 11 | inherit name; 12 | type = "frapper"; 13 | actions = { 14 | currentSystem, 15 | fragment, 16 | fragmentRelPath, 17 | target, 18 | inputs, 19 | }: [(actions.run currentSystem target)]; 20 | } 21 | -------------------------------------------------------------------------------- /apps/sources/drive.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "drive"; 3 | version = "v0.1.0-alpha"; 4 | meta = { 5 | url = "https://github.com/frappe/drive/releases/tag/v0.1.0-alpha"; 6 | description = "Sources for drive (v0.1.0-alpha)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "github"; 10 | owner = "frappe"; repo = "drive"; 11 | narHash = "sha256-XP0a09lzO74dHe5ya+XrGD3oHp2YvDnAl2fIgRpv+B4="; 12 | rev = "6188a854652adb9702f78efbc35645d0aecd1a2e"; 13 | }; 14 | passthru = builtins.fromJSON ''{}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/crm.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "crm"; 3 | version = "v1.39.1"; 4 | meta = { 5 | url = "https://github.com/frappe/crm/releases/tag/v1.39.1"; 6 | description = "Sources for crm (v1.39.1)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "git"; 10 | url = "https://github.com/frappe/crm.git"; submodules = true; allRefs = true; 11 | narHash = "sha256-ILiVSDT6SLmxhPFkPIf8qL5cZD1aAB1xuKy2zioOYxg="; 12 | rev = "bf4da21153d2f1caab45f3e11f95cbea119368e5"; 13 | }; 14 | passthru = builtins.fromJSON ''{}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/wiki.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "wiki"; 3 | version = "20250321.124101"; 4 | meta = { 5 | url = "https://github.com/frappe/wiki/commit/2f52aac6a7e5a55e3e1f77557e8bacc6f8b4cb54"; 6 | description = "Sources for wiki (20250321.124101)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "github"; 10 | owner = "frappe"; repo = "wiki"; 11 | narHash = "sha256-2XyvpF/KGZxl17JhFkb6MsOcgLheEd+uKgG7JBaEF9w="; 12 | rev = "2f52aac6a7e5a55e3e1f77557e8bacc6f8b4cb54"; 13 | }; 14 | passthru = builtins.fromJSON ''{}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/bench.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "bench"; 3 | version = "20250320.162429"; 4 | meta = { 5 | url = "https://github.com/frappe/bench/commit/360acd3dc225e8a70a68b4b14553f8a35b1b9dc8"; 6 | description = "Sources for bench (20250320.162429)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "github"; 10 | owner = "frappe"; repo = "bench"; 11 | narHash = "sha256-NgV0aXELHsSTdwDgfinMO8KM1qarCxD9W4C6uMvgBY4="; 12 | rev = "360acd3dc225e8a70a68b4b14553f8a35b1b9dc8"; 13 | }; 14 | passthru = builtins.fromJSON ''{}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/hrms.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "hrms"; 3 | version = "v15.41.0"; 4 | meta = { 5 | url = "https://github.com/frappe/hrms/releases/tag/v15.41.0"; 6 | description = "Sources for hrms (v15.41.0)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "git"; 10 | url = "https://github.com/frappe/hrms.git"; submodules = true; allRefs = true; 11 | narHash = "sha256-t5E+Z6wDFIB3ubc8fnysf3cDDtMIHwhnbcGcDQdpJ4Y="; 12 | rev = "461897bf67966657b3eb0491113713d38f6c1e07"; 13 | }; 14 | passthru = builtins.fromJSON ''{}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/builder.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "builder"; 3 | version = "v1.15.0"; 4 | meta = { 5 | url = "https://github.com/frappe/builder/releases/tag/v1.15.0"; 6 | description = "Sources for builder (v1.15.0)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "git"; 10 | url = "https://github.com/frappe/builder.git"; submodules = true; allRefs = true; 11 | narHash = "sha256-r8ElYlhRs5SghU5MVJh072FrtVqTL/HACL7twTMmTXk="; 12 | rev = "5d3653e131cb14c3bdc3023a34ca9f4e639ea243"; 13 | }; 14 | passthru = builtins.fromJSON ''{}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/webshop.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "webshop"; 3 | version = "20250322.101439"; 4 | meta = { 5 | url = "https://github.com/frappe/webshop/commit/0ff095bb7d17136c8fec6f3e05535baef0a90272"; 6 | description = "Sources for webshop (20250322.101439)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "github"; 10 | owner = "frappe"; repo = "webshop"; 11 | narHash = "sha256-uH9mpApPzonWqBnhkNKrffp3ve5ZKSY/S+fYQQc81o4="; 12 | rev = "0ff095bb7d17136c8fec6f3e05535baef0a90272"; 13 | }; 14 | passthru = builtins.fromJSON ''{}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/insights.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "insights"; 3 | version = "v3.0.24"; 4 | meta = { 5 | url = "https://github.com/frappe/insights/releases/tag/v3.0.24"; 6 | description = "Sources for insights (v3.0.24)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "git"; 10 | url = "https://github.com/frappe/insights.git"; submodules = true; allRefs = true; 11 | narHash = "sha256-5x+EbxPWlcGtUxqisHQA6LKiUqK9oDGY9DW0DBhoK90="; 12 | rev = "406ac82e230e6ba84c67774530bd41001f680ed0"; 13 | }; 14 | passthru = builtins.fromJSON ''{}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/payments.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "payments"; 3 | version = "20250318.104949"; 4 | meta = { 5 | url = "https://github.com/frappe/payments/commit/a2ed721365d45f3e70d2233f547382cf2443ab00"; 6 | description = "Sources for payments (20250318.104949)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "github"; 10 | owner = "frappe"; repo = "payments"; 11 | narHash = "sha256-xSXBvMvlsPD+wr19H7kGyDDVEDjC8x4loqzWHJ6p36U="; 12 | rev = "a2ed721365d45f3e70d2233f547382cf2443ab00"; 13 | }; 14 | passthru = builtins.fromJSON ''{}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/print-designer.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "print-designer"; 3 | version = "v1.4.3"; 4 | meta = { 5 | url = "https://github.com/frappe/print_designer/releases/tag/v1.4.3"; 6 | description = "Sources for print-designer (v1.4.3)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "github"; 10 | owner = "frappe"; 11 | repo = "print_designer"; 12 | narHash = "sha256-CuLTTECeiHppqzSCKcHqw3Vy9gHVIcMarFWSKTc+REU="; 13 | rev = "ff474bb6aa3b304adda8cc08c4d12a2d3320ecd7"; 14 | }; 15 | passthru = builtins.fromJSON ''{}''; 16 | } 17 | -------------------------------------------------------------------------------- /apps/sources.md: -------------------------------------------------------------------------------- 1 | # App Sources 2 | 3 | This block holds all Frappé app sources. 4 | 5 | You can update them by running the command `nvchecker -c sources/config.toml` within this directory. 6 | 7 | To configure how new versions should be discovered, or to add a new source, 8 | you can use set the corresponding values in `nvchecker` according to the official documentation of the tool. 9 | 10 | We use a private patch that generates the nix files for us after checking for an update. 11 | See https://github.com/lilydjwg/nvchecker/pull/253 until a better place is found. 12 | -------------------------------------------------------------------------------- /local/Readme.md: -------------------------------------------------------------------------------- 1 | # Hacking on Frappix 2 | 3 | Frappix' `./local` cell contrains the full specification of the local contribution environment. 4 | 5 | If you don't have Nix installed, you can start contributing by simply run the following command: 6 | 7 | ```console 8 | bash <(curl -L https://blaggacao.github.io/frappix/install) 9 | ``` 10 | 11 | This will install, if not already: 12 | 13 | - Nix: _orchestrate the environment_ 14 | - Direnv: _enable the environment when entering the folder_ 15 | - Frx: _the frappix tool, can be also used on your Frappix projects_ 16 | -------------------------------------------------------------------------------- /examples/templates/frappe/apps/_pins.nix: -------------------------------------------------------------------------------- 1 | let 2 | inherit (builtins) readDir; 3 | inherit (inputs.nixpkgs) lib; 4 | 5 | fileIsNix = basename: type: type == "regular" && lib.hasSuffix ".nix" basename && basename != "default.nix"; 6 | 7 | loadPath = path: name: _: import (lib.path.append path name); 8 | 9 | sourceDirectoryEntries = path: lib.mapAttrs (loadPath path) (lib.filterAttrs fileIsNix (readDir path)); 10 | 11 | sanitizeKey = name: attrs: lib.nameValuePair (lib.removeSuffix ".nix" name) attrs; 12 | in 13 | lib.mapAttrs' sanitizeKey (sourceDirectoryEntries ./_pins) 14 | -------------------------------------------------------------------------------- /apps/sources/gameplan.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "gameplan"; 3 | version = "20250303.100259"; 4 | meta = { 5 | url = "https://github.com/frappe/gameplan/commit/39202bc2e590ffd04d50ef53f72250b5cea27fd3"; 6 | description = "Sources for gameplan (20250303.100259)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "git"; 10 | url = "https://github.com/frappe/gameplan.git"; submodules = true; allRefs = true; 11 | narHash = "sha256-1KgmooET4jz09pOn3KEY+hiDsauowW/Ky9YXLFUqN3A="; 12 | rev = "39202bc2e590ffd04d50ef53f72250b5cea27fd3"; 13 | }; 14 | passthru = builtins.fromJSON ''{}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/ecommerce-integrations.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "ecommerce-integrations"; 3 | version = "20241008.043734"; 4 | meta = { 5 | url = "https://github.com/frappe/ecommerce_integrations/commit/160b119a61555f1c5d62877e796e743a26e7ede8"; 6 | description = "Sources for ecommerce-integrations (20241008.043734)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "github"; 10 | owner = "frappe"; 11 | repo = "ecommerce_integrations"; 12 | narHash = "sha256-nXxt5mku05OLHdy+Sn6WJCN8tl54GBRj+ZI3ZhrGtFI="; 13 | rev = "160b119a61555f1c5d62877e796e743a26e7ede8"; 14 | }; 15 | passthru = builtins.fromJSON ''{}''; 16 | } 17 | -------------------------------------------------------------------------------- /apps/sources/raven.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "raven"; 3 | version = "v2.1.10"; 4 | meta = { 5 | url = "https://github.com/The-Commit-Company/Raven/releases/tag/v2.1.10"; 6 | description = "Sources for raven (v2.1.10)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "github"; 10 | owner = "The-Commit-Company"; repo = "Raven"; 11 | narHash = "sha256-tb84LXoW0tvThdPOJbPfwWCM1DngyK43FqdXDerJqqw="; 12 | rev = "ee28fb922ea86ee07435a31444b489dc154264c8"; 13 | }; 14 | passthru = builtins.fromJSON ''{"since": "v1.0.0", "upstream": "URL: https://github.com/The-Commit-Company/Raven\nPull: +refs/heads/develop:refs/remotes/upstream/develop\nPull: +refs/heads/main:refs/remotes/upstream/main\n"}''; 15 | } -------------------------------------------------------------------------------- /src/overlays/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | python = { 3 | __functor = _: final: prev: { 4 | pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [(import ./python)]; 5 | }; 6 | meta.description = "Frappix python overlays"; 7 | }; 8 | 9 | frappe = { 10 | __functor = import ./frappe; 11 | inherit (inputs.cells.apps) sources; # providing: frappe, erpnext, ... 12 | meta.description = "Frappix stock overlays"; 13 | }; 14 | 15 | tools = { 16 | __functor = _: (import ./tools inputs); 17 | meta.description = "Frappix tools overlays"; 18 | }; 19 | 20 | libs = { 21 | __functor = _: (import ./libs inputs); 22 | meta.description = "Frappix additional libs and native binaries"; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /apps/sources/frappe-website-generator.patch: -------------------------------------------------------------------------------- 1 | diff --git a/frappe/website/doctype/website_theme/website_theme.py b/frappe/website/doctype/website_theme/website_theme.py 2 | index d5d67e325a..23adf9140e 100644 3 | --- a/frappe/website/doctype/website_theme/website_theme.py 4 | +++ b/frappe/website/doctype/website_theme/website_theme.py 5 | @@ -108,7 +108,7 @@ class WebsiteTheme(Document): 6 | content = content.replace("\n", "\\n") 7 | command = ["node", "generate_bootstrap_theme.js", output_path, content] 8 | 9 | - process = Popen(command, cwd=frappe.get_app_source_path("frappe"), stdout=PIPE, stderr=PIPE) 10 | + process = Popen(command, cwd="@frappe@", stdout=PIPE, stderr=PIPE) 11 | 12 | stderr = process.communicate()[1] 13 | 14 | -------------------------------------------------------------------------------- /examples/templates/frappe/tools/shells.nix: -------------------------------------------------------------------------------- 1 | /* 2 | This file holds reproducible shells with commands in them. 3 | 4 | They conveniently also generate config files in their startup hook. 5 | */ 6 | let 7 | inherit (inputs.std.lib) dev; 8 | inherit (inputs.frappix) shellModule; 9 | inherit (inputs.cells.apps) pkgs; 10 | in { 11 | # Tool Homepage: https://numtide.github.io/devshell/ 12 | default = 13 | (dev.mkShell { 14 | name = "Frappix Shell"; 15 | pkgs = pkgs; 16 | imports = [shellModule]; 17 | 18 | bench.enableExtraProjectTools = false; 19 | bench.apps = with pkgs.frappix; [ 20 | # my-app 21 | ]; 22 | }) 23 | // {meta.description = "Development environment for this repository";}; 24 | } 25 | -------------------------------------------------------------------------------- /src/overlays/python/email-reply-parser.nix: -------------------------------------------------------------------------------- 1 | # https://github.com/NixOS/nixpkgs/pull/244735 2 | { 3 | lib, 4 | buildPythonPackage, 5 | fetchFromGitHub, 6 | }: 7 | buildPythonPackage rec { 8 | pname = "email-reply-parser"; 9 | version = "0.5.12"; 10 | format = "setuptools"; 11 | 12 | src = fetchFromGitHub { 13 | owner = "zapier"; 14 | repo = "email-reply-parser"; 15 | rev = "v${version}"; 16 | hash = "sha256-UFyqYVvZMQ46Ph9h6Z21t1sDS4QTmjeJMFZjBiWOJNs="; 17 | }; 18 | 19 | pythonImportsCheck = ["email_reply_parser"]; 20 | 21 | meta = with lib; { 22 | description = "Library to parse the last reply in emails"; 23 | homepage = "https://github.com/zapier/email-reply-parser"; 24 | license = licenses.mit; 25 | maintainers = with maintainers; [blaggacao]; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /apps/sources/erpnext.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "erpnext"; 3 | version = "v15.54.5"; 4 | meta = { 5 | url = "https://github.com/frappe/erpnext/releases/tag/v15.54.5"; 6 | description = "Sources for erpnext (v15.54.5)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "github"; 10 | owner = "frappe"; repo = "erpnext"; 11 | narHash = "sha256-gKO3WDbaS+8iGX+T4N0KNE8hGT34cGRK3LhVPkQ8FBw="; 12 | rev = "35ac96f1ec09de17916c447e172e8464f3c160be"; 13 | }; 14 | passthru = builtins.fromJSON ''{"since": "version-14", "upstream": "URL: https://github.com/frappe/erpnext\nPull: +refs/heads/develop:refs/remotes/upstream/develop\nPull: +refs/heads/version-15:refs/remotes/upstream/version-15\nPull: +refs/heads/version-15-hotfix:refs/remotes/upstream/version-15-hotfix\nPull: +refs/tags/v15.*:refs/remotes/upstream/tags/v15.*\n"}''; 15 | } -------------------------------------------------------------------------------- /apps/sources/frappe.nix: -------------------------------------------------------------------------------- 1 | { 2 | pname = "frappe"; 3 | version = "v15.60.0"; 4 | meta = { 5 | url = "https://github.com/frappe/frappe/releases/tag/v15.60.0"; 6 | description = "Sources for frappe (v15.60.0)"; 7 | }; 8 | src = builtins.fetchTree { 9 | type = "github"; 10 | owner = "frappe"; repo = "frappe"; 11 | narHash = "sha256-JoZfT0ZAVV76voyANlLOn15FgjdGMLT1L+30KZmvVQQ="; 12 | rev = "b38a313be1d63e41160115af3e359af0fd977ed8"; 13 | }; 14 | passthru = builtins.fromJSON ''{"clone": {"since": "version-14", "upstream": {"fetch": ["+refs/heads/develop:refs/remotes/upstream/develop", "+refs/heads/version-15:refs/remotes/upstream/version-15", "+refs/heads/version-15-hotfix:refs/remotes/upstream/version-15-hotfix", "+refs/tags/v15.*:refs/remotes/upstream/tags/v15.*"], "url": "https://github.com/frappe/frappe"}}}''; 15 | } -------------------------------------------------------------------------------- /src/overlays/python/paytmchecksum.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchFromGitHub, 5 | pycryptodome, 6 | }: 7 | buildPythonPackage rec { 8 | pname = "paytm-python-checksum"; 9 | version = "unstable-2023-08-02"; 10 | format = "setuptools"; 11 | 12 | propagatedBuildInputs = [ 13 | pycryptodome 14 | ]; 15 | 16 | src = fetchFromGitHub { 17 | owner = "paytm"; 18 | repo = "Paytm_Python_Checksum"; 19 | rev = "f1efd1d4e6b2524417437760910729486f4869b8"; 20 | hash = "sha256-h6DBaqKGOKnYwXjCVmQ8EYhOMbhRDXJDJjlQfY3p94s="; 21 | }; 22 | 23 | pythonImportsCheck = ["paytmchecksum"]; 24 | 25 | meta = with lib; { 26 | description = ""; 27 | homepage = "https://github.com/paytm/Paytm_Python_Checksum.git"; 28 | license = licenses.mit; 29 | maintainers = with maintainers; []; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/oci.nix: -------------------------------------------------------------------------------- 1 | { 2 | frappix = { 3 | meta.description = "The main frappix OCI module"; 4 | __functor = _: { 5 | pkgs, 6 | lib, 7 | ... 8 | }: { 9 | # load our custom `pkgs` 10 | _module.args = { 11 | inherit (pkgs) frappix; 12 | inherit (inputs.std.lib) ops; 13 | }; 14 | _file = ./oci.nix; 15 | imports = map (m: lib.modules.setDefaultModuleLocation m m) [ 16 | ./oci/main.nix 17 | ]; 18 | }; 19 | }; 20 | testrig = { 21 | meta.description = "The frappix example OCI image profile"; 22 | __functor = _: { 23 | pkgs, 24 | lib, 25 | ... 26 | }: { 27 | _file = ./oci.nix; 28 | imports = map (m: lib.modules.setDefaultModuleLocation m m) [ 29 | (import ./oci/testrig.nix inputs) 30 | ]; 31 | }; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /src/nixos.nix: -------------------------------------------------------------------------------- 1 | { 2 | frappix = { 3 | meta.description = "The main frappix nixos module"; 4 | __functor = _: { 5 | pkgs, 6 | lib, 7 | ... 8 | }: { 9 | # load our custom `pkgs` 10 | _module.args = { 11 | inherit (pkgs) frappix; 12 | }; 13 | _file = ./nixos.nix; 14 | imports = map (m: lib.modules.setDefaultModuleLocation m m) [ 15 | ./nixos/main.nix 16 | ./nixos/systemd.nix 17 | ./nixos/nginx.nix 18 | ]; 19 | }; 20 | }; 21 | testrig = { 22 | meta.description = "The frappix nixos testrig mixin module"; 23 | __functor = _: { 24 | pkgs, 25 | lib, 26 | ... 27 | }: { 28 | _file = ./nixos.nix; 29 | imports = map (m: lib.modules.setDefaultModuleLocation m m) [ 30 | ./nixos/testrig.nix 31 | ]; 32 | }; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/overlays/frappe/wiki/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | extractFrappeMeta, 8 | mkAssets, 9 | }: 10 | buildPythonPackage rec { 11 | inherit 12 | (extractFrappeMeta src) 13 | format 14 | ; # We can't extract anything other than format because pyproject.toml does not have the information 15 | 16 | pname = "wiki"; 17 | version = "3.x-dev"; 18 | 19 | src = mkAssets appSources.wiki; 20 | inherit (appSources.wiki) passthru; 21 | 22 | nativeBuildInputs = [ 23 | pythonRelaxDepsHook 24 | flit-core 25 | ]; 26 | 27 | meta = with lib; { 28 | description = "Modern, Feature-Rich Wiki Application"; 29 | homepage = "https://github.com/frappe/wiki"; 30 | license = licenses.mit; 31 | maintainers = with maintainers; [minion3665]; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /src/overlays/python/linkpreview.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchPypi, 5 | setuptools, 6 | wheel, 7 | beautifulsoup4, 8 | requests, 9 | }: 10 | buildPythonPackage rec { 11 | pname = "linkpreview"; 12 | version = "0.9.0"; 13 | pyproject = true; 14 | 15 | src = fetchPypi { 16 | inherit pname version; 17 | hash = "sha256-9aHxeJU1AfF/YGAV6XkkW7qA4NY+5MqnnqYly/UkFe8="; 18 | }; 19 | 20 | build-system = [ 21 | setuptools 22 | wheel 23 | ]; 24 | 25 | dependencies = [ 26 | beautifulsoup4 27 | requests 28 | ]; 29 | 30 | pythonImportsCheck = [ 31 | "linkpreview" 32 | ]; 33 | 34 | meta = with lib; { 35 | description = "Get link (URL) preview"; 36 | homepage = "https://pypi.org/project/linkpreview/"; 37 | license = licenses.mit; 38 | maintainers = with maintainers; []; 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /src/overlays/frappe/webshop.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | flit-core, 6 | pythonRelaxDepsHook, 7 | extractFrappeMeta, 8 | mkAssets, 9 | }: 10 | buildPythonPackage rec { 11 | inherit 12 | (extractFrappeMeta src) 13 | pname 14 | version 15 | format 16 | ; 17 | 18 | src = mkAssets appSources.webshop; 19 | inherit (appSources.webshop) passthru; 20 | 21 | nativeBuildInputs = [ 22 | pythonRelaxDepsHook 23 | flit-core 24 | ]; 25 | 26 | # would require frappe, but since frappe is almost certainly customized, 27 | # we don't include it here / TODO: decide if we may actually add it? 28 | # pythonImportsCheck = ["webshop"]; 29 | 30 | meta = with lib; { 31 | description = "Frappe webshop is an Open Source eCommerce Platform"; 32 | homepage = "https://github.com/frappe/webshop.git"; 33 | license = licenses.gpl3; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /src/overlays/python/sql_metadata.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchFromGitHub, 5 | poetry-core, 6 | sqlparse, 7 | }: 8 | buildPythonPackage rec { 9 | pname = "sql_metadata"; 10 | version = "2.12.0"; 11 | pyproject = true; 12 | 13 | src = fetchFromGitHub { 14 | owner = "macbre"; 15 | repo = "sql-metadata"; 16 | rev = "v${version}"; 17 | hash = "sha256-oY/EJ1RdMvMrZksAcaMATIVuBvUkqI6x9cL9iGcZ8Eo="; 18 | }; 19 | 20 | build-system = [ 21 | poetry-core 22 | ]; 23 | 24 | dependencies = [ 25 | sqlparse 26 | ]; 27 | 28 | pythonImportsCheck = [ 29 | "sql_metadata" 30 | ]; 31 | 32 | meta = with lib; { 33 | description = "Uses tokenized query returned by python-sqlparse and generates query metadata"; 34 | homepage = "https://github.com/macbre/sql-metadata"; 35 | license = licenses.mit; 36 | maintainers = with maintainers; []; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /src/overlays/python/barcodenumber.nix: -------------------------------------------------------------------------------- 1 | # https://github.com/NixOS/nixpkgs/pull/242577 2 | { 3 | lib, 4 | buildPythonPackage, 5 | fetchPypi, 6 | python-stdnum, 7 | }: 8 | buildPythonPackage rec { 9 | pname = "barcodenumber"; 10 | version = "0.5.0"; 11 | format = "wheel"; 12 | 13 | # Bitbucket repo is no longer public or does no longer exist 14 | src = fetchPypi { 15 | inherit pname version format; 16 | dist = "py3"; 17 | python = "py3"; 18 | hash = "sha256-VZfHLwSF9aDoy5L1x4O2mu8/f2ijYKgyjCrQ1KKY5Ho="; 19 | }; 20 | 21 | propagatedBuildInputs = [ 22 | python-stdnum 23 | ]; 24 | 25 | pythonImportsCheck = ["barcodenumber"]; 26 | 27 | meta = with lib; { 28 | description = "Python module to validate product codes"; 29 | homepage = "https://pypi.org/project/barcodenumber/"; 30 | license = licenses.gpl3Only; 31 | maintainers = with maintainers; [blaggacao]; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /src/overlays/python/premailer.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchPypi, 5 | isPy27, 6 | cssselect, 7 | cssutils, 8 | lxml, 9 | mock, 10 | requests, 11 | cachetools, 12 | }: 13 | buildPythonPackage rec { 14 | pname = "premailer"; 15 | version = "3.10.0"; 16 | format = "setuptools"; 17 | disabled = isPy27; # no longer compatible with urllib 18 | 19 | src = fetchPypi { 20 | inherit pname version; 21 | sha256 = "d1875a8411f5dc92b53ef9f193db6c0f879dc378d618e0ad292723e388bfe4c2"; 22 | }; 23 | 24 | buildInputs = [ 25 | mock 26 | ]; 27 | propagatedBuildInputs = [ 28 | cachetools 29 | cssselect 30 | cssutils 31 | lxml 32 | requests 33 | ]; 34 | doCheck = false; 35 | 36 | meta = { 37 | description = "Turns CSS blocks into style attributes"; 38 | homepage = "https://github.com/peterbe/premailer"; 39 | license = lib.licenses.bsd3; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/overlays/python/plaid-python.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchPypi, 5 | setuptools, 6 | wheel, 7 | nulltype, 8 | python-dateutil, 9 | urllib3, 10 | requests, 11 | }: 12 | buildPythonPackage rec { 13 | pname = "plaid-python"; 14 | version = "7.2.1"; 15 | pyproject = true; 16 | 17 | src = fetchPypi { 18 | inherit pname version; 19 | hash = "sha256-ryrTJug3fIyG2XGE9gwL5BzXH1B1IB39szMcyF1N5RM="; 20 | }; 21 | 22 | nativeBuildInputs = [ 23 | setuptools 24 | wheel 25 | ]; 26 | 27 | propagatedBuildInputs = [ 28 | nulltype 29 | python-dateutil 30 | urllib3 31 | requests 32 | ]; 33 | 34 | pythonImportsCheck = ["plaid"]; 35 | 36 | meta = with lib; { 37 | description = "Python client library for the Plaid API and Link"; 38 | homepage = "https://pypi.org/project/plaid-python/"; 39 | license = licenses.mit; 40 | maintainers = with maintainers; []; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /src/overlays/python/json-source-map.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchFromGitHub, 5 | poetry-core, 6 | }: 7 | buildPythonPackage rec { 8 | pname = "json-source-map"; 9 | version = "1.0.5"; 10 | format = "pyproject"; 11 | 12 | src = fetchFromGitHub { 13 | owner = "open-alchemy"; 14 | repo = "json-source-map"; 15 | rev = "v${version}"; 16 | hash = "sha256-SmzvgywSUxrGyM+1TJlOPuOyF4SxTZBxbLI61G6752M="; 17 | }; 18 | 19 | nativeBuildInputs = [ 20 | poetry-core 21 | ]; 22 | 23 | pythonImportsCheck = ["json_source_map"]; 24 | 25 | meta = with lib; { 26 | description = "Calculate JSON Pointers to each value within a JSON document"; 27 | homepage = "https://github.com/open-alchemy/json-source-map"; 28 | changelog = "https://github.com/open-alchemy/json-source-map/blob/${src.rev}/CHANGELOG.md"; 29 | license = licenses.mit; 30 | maintainers = with maintainers; [blaggacao]; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/overlays/python/razorpay.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchFromGitHub, 5 | requests, 6 | responses, 7 | }: 8 | buildPythonPackage rec { 9 | pname = "razorpay-python"; 10 | version = "1.4.1"; 11 | format = "setuptools"; 12 | 13 | src = fetchFromGitHub { 14 | owner = "razorpay"; 15 | repo = "razorpay-python"; 16 | rev = "v${version}"; 17 | hash = "sha256-PXfyPC4/5MZdnU6hhRS+R3PFybp0TeQbnV5VJt0n+uI="; 18 | }; 19 | 20 | propagatedBuildInputs = [ 21 | requests 22 | ]; 23 | 24 | pythonImportsCheck = ["razorpay"]; 25 | 26 | nativeCheckInputs = [ 27 | responses 28 | ]; 29 | 30 | meta = with lib; { 31 | description = "Razorpay Python SDK"; 32 | homepage = "https://github.com/razorpay/razorpay-python.git"; 33 | changelog = "https://github.com/razorpay/razorpay-python/blob/${src.rev}/CHANGELOG.md"; 34 | license = licenses.mit; 35 | maintainers = with maintainers; []; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /std/nvchecker.nix: -------------------------------------------------------------------------------- 1 | {inputs}: name: { 2 | __functor = _: self: selectors: self // selectors; 3 | inherit name; 4 | type = "nvchecker"; 5 | actions = { 6 | currentSystem, 7 | fragment, 8 | fragmentRelPath, 9 | target, 10 | inputs, 11 | }: let 12 | pkgs = inputs.nixpkgs.${currentSystem}; 13 | in [ 14 | { 15 | name = "fetch"; 16 | description = "update source"; 17 | command = 18 | pkgs.writers.writeBash "fetch" 19 | # we can't use this package since its not patched 20 | # bacause it's packaged within this repo we also 21 | # have no handle onto it for block types 22 | # pkgs.nvchecker 23 | '' 24 | targetname="$(basename ${fragmentRelPath})" 25 | blockpath="$(dirname ${fragmentRelPath})" 26 | nvchecker \ 27 | --file "$PRJ_ROOT/$blockpath/config.toml" \ 28 | --entry "$targetname" 29 | ''; 30 | } 31 | ]; 32 | } 33 | -------------------------------------------------------------------------------- /src/oci/testrig.nix: -------------------------------------------------------------------------------- 1 | inputs: {pkgs, ...}: { 2 | oci.frappix = { 3 | name = "ghcr.io/blaggacao/frappix-test-oci"; 4 | debug = false; 5 | apps = let 6 | appList = builtins.attrNames (builtins.removeAttrs inputs.cells.apps.sources [ 7 | "bench" # not an app 8 | "frappe" # automatically added; don't add twice 9 | "builder" # brakes via https://github.com/frappe/builder/commit/cae39ff422812b52d3c1b25ae4756669add794d1#commitcomment-148362353 10 | "crm" # brakes via https://github.com/frappe/crm/commit/a439433977321188266ff38cdef09642e4166080#commitcomment-148363342 11 | "drive" # waiting on https://github.com/blaggacao/frappix/pull/11 12 | "gameplan" # brakes via https://github.com/blaggacao/frappix/issues/18#issuecomment-2619829870 13 | "insights" # brakes via https://github.com/blaggacao/frappix/issues/18#issuecomment-2619860284 14 | ]); 15 | in 16 | map (name: pkgs.frappix.${name}) appList; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/overlays/tools/start-mariadb-for-frappe.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | writers, 4 | mariadb, 5 | }: let 6 | mariadbd = "${mariadb}/bin/mariadbd"; 7 | mariadb-admin = "${mariadb}/bin/mariadb-admin"; 8 | mariadb-install-db = "${mariadb}/bin/mariadb-install-db"; 9 | in 10 | lib.lazyDerivation { 11 | derivation = writers.writeBashBin "start-mariadb-for-frappe" '' 12 | set -euo pipefail 13 | 14 | args=() 15 | args+=("--collation-server=utf8mb4_unicode_ci") 16 | args+=("--datadir=$MYSQL_HOME") 17 | args+=("--basedir=$DEVSHELL_DIR") 18 | 19 | if [[ ! -d "$MYSQL_HOME" || ! -f "$MYSQL_HOME/ibdata1" ]]; then 20 | mkdir -p "$MYSQL_HOME" 21 | ${mariadb-install-db} ''${args[@]} 22 | fi 23 | 24 | ${mariadbd} ''${args[@]} & 25 | PID=`jobs -p` 26 | 27 | trap "kill -SIGTERM $PID && wait $PID" INT EXIT 28 | 29 | wait 30 | ''; 31 | meta.description = "Start (and initialize) MariaDB with frappe's config"; 32 | } 33 | -------------------------------------------------------------------------------- /src/overlays/frappe/raven/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | python, 8 | extractFrappeMeta, 9 | mkAssets, 10 | }: 11 | buildPythonPackage rec { 12 | inherit 13 | (extractFrappeMeta src) 14 | pname 15 | version 16 | format 17 | ; 18 | 19 | src = mkAssets appSources.raven; 20 | inherit (appSources.raven) passthru; 21 | 22 | nativeBuildInputs = [ 23 | pythonRelaxDepsHook 24 | flit-core 25 | ]; 26 | 27 | propagatedBuildInputs = with python.pkgs; [ 28 | linkpreview 29 | openai 30 | ]; 31 | 32 | # pythonRemoveDeps = [ 33 | # "rembg" # TODO: package 34 | # ]; 35 | 36 | # pythonImportsCheck = ["gameplan"]; 37 | 38 | meta = with lib; { 39 | description = "Simple, open source team messaging platform"; 40 | homepage = "https://github.com/The-Commit-Company/Raven"; 41 | license = licenses.agpl3Only; 42 | maintainers = with maintainers; [blaggacao]; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /src/overlays/frappe/hrms-0001-build-socket-port-is-reverse-proxied.patch: -------------------------------------------------------------------------------- 1 | diff --git a/frontend/src/socket.js b/frontend/src/socket.js 2 | index a942ea6fc..aad13cef4 100644 3 | --- a/frontend/src/socket.js 4 | +++ b/frontend/src/socket.js 5 | @@ -1,5 +1,4 @@ 6 | import { io } from "socket.io-client" 7 | -import { socketio_port } from "../../../../sites/common_site_config.json" 8 | 9 | import { getCachedListResource } from "frappe-ui/src/resources/listResource" 10 | import { getCachedResource } from "frappe-ui/src/resources/resources" 11 | @@ -7,9 +6,7 @@ import { getCachedResource } from "frappe-ui/src/resources/resources" 12 | export function initSocket() { 13 | let host = window.location.hostname 14 | let siteName = window.site_name 15 | - let port = window.location.port ? `:${socketio_port}` : "" 16 | - let protocol = port ? "http" : "https" 17 | - let url = `${protocol}://${host}${port}/${siteName}` 18 | + let url = `https://${host}/${siteName}` 19 | let socket = io(url, { 20 | withCredentials: true, 21 | reconnectionAttempts: 5, 22 | -------------------------------------------------------------------------------- /src/overlays/frappe/default.nix: -------------------------------------------------------------------------------- 1 | self: final: prev: let 2 | inherit (final) lib; 3 | inherit (final) python3; 4 | newScope = extra: lib.callPackagesWith ({} // extra); 5 | in { 6 | frappix = lib.makeScope python3.pkgs.newScope (scope: let 7 | inherit (scope) callPackage; 8 | in { 9 | appSources = lib.makeScope newScope (_: self.sources); 10 | 11 | frappe = callPackage ./frappe.nix {}; 12 | erpnext = callPackage ./erpnext.nix {}; 13 | 14 | builder = callPackage ./builder.nix {}; 15 | ecommerce-integrations = callPackage ./ecommerce-integrations.nix {}; 16 | gameplan = callPackage ./gameplan {}; 17 | crm = callPackage ./crm.nix {}; 18 | hrms = callPackage ./hrms.nix {}; 19 | insights = callPackage ./insights.nix {}; 20 | payments = callPackage ./payments.nix {}; 21 | print-designer = callPackage ./print-designer.nix {}; 22 | webshop = callPackage ./webshop.nix {}; 23 | wiki = callPackage ./wiki {}; 24 | raven = callPackage ./raven {}; 25 | drive = callPackage ./drive {}; 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /src/overlays/frappe/hrms.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | extractFrappeMeta, 8 | mkAssets, 9 | applyPatches, 10 | }: 11 | buildPythonPackage rec { 12 | inherit 13 | (extractFrappeMeta src) 14 | pname 15 | version 16 | format 17 | ; 18 | 19 | src = mkAssets (appSources.hrms 20 | // { 21 | src = applyPatches { 22 | inherit (appSources.hrms) src; 23 | name = "hrms-prod"; 24 | patches = [ 25 | ./hrms-0001-build-socket-port-is-reverse-proxied.patch 26 | ]; 27 | }; 28 | }); 29 | inherit (appSources.hrms) passthru; 30 | 31 | nativeBuildInputs = [ 32 | pythonRelaxDepsHook 33 | flit-core 34 | ]; 35 | 36 | # pythonImportsCheck = ["hrms"]; 37 | 38 | meta = with lib; { 39 | description = "Open Source HR & Payroll Software"; 40 | homepage = "https://github.com/frappe/hrms"; 41 | license = licenses.agpl3Only; 42 | maintainers = with maintainers; [blaggacao]; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /src/overlays/frappe/builder.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | python, 8 | extractFrappeMeta, 9 | mkAssets, 10 | }: 11 | buildPythonPackage rec { 12 | inherit 13 | (extractFrappeMeta src) 14 | pname 15 | version 16 | format 17 | ; 18 | 19 | src = mkAssets appSources.builder; 20 | inherit (appSources.builder) passthru; 21 | 22 | nativeBuildInputs = [ 23 | pythonRelaxDepsHook 24 | flit-core 25 | ]; 26 | 27 | propagatedBuildInputs = with python.pkgs; [ 28 | ]; 29 | 30 | pythonRelaxDeps = [ 31 | ]; 32 | 33 | # would require frappe, but since frappe is almost certainly customized, 34 | # we don't include it here / TODO: decide if we may actually add it? 35 | # pythonImportsCheck = ["erpnext"]; 36 | 37 | meta = with lib; { 38 | description = "Modern website builder for modern web pages"; 39 | homepage = "https://github.com/frappe/builder"; 40 | license = licenses.agpl3Only; 41 | maintainers = with maintainers; [blaggacao]; 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /docs/run-tests.md: -------------------------------------------------------------------------------- 1 | # Run tests 2 | 3 | - Use the test rig module 4 | - Build the VM 5 | - Run it 6 | - Run tests 7 | 8 | **Example of using the test rig module:** 9 | 10 | ```nix 11 | let 12 | # [...] 13 | inherit (inputs.frappix.nixosModules) testrig frappix; 14 | in rec { 15 | test-HOST = { 16 | config, 17 | lib, 18 | ... 19 | }: { 20 | imports = [ 21 | HOST 22 | testrig 23 | ]; 24 | # maybe some manual adjustments and override necessary for the test 25 | }; 26 | HOST = { 27 | # your production config 28 | }; 29 | } 30 | ``` 31 | 32 | **Build the VM with:** 33 | 34 | TODO: incorporate into `frx` more elegantly 35 | 36 | `nix build .\#nixosConfigurations.deploy-test-HOST.config.system.build.vm` 37 | 38 | **Run the VM in headless mode:** 39 | 40 | - `sudo` ensures we can bind to the low ports `80` & `443` to fully test the VM 41 | 42 | ```console 43 | # launch the VM 44 | QEMU_NET_OPTS="hostfwd=tcp:127.0.0.1:2222-:22" sudo ./result/bin/run-HOST-vm; reset 45 | ``` 46 | 47 | **TODO: Run tests:** 48 | 49 | Just run ... 50 | 51 | ```console 52 | bench ... 53 | ``` 54 | -------------------------------------------------------------------------------- /src/overlays/python/pyactiveresource.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchFromGitHub, 5 | setuptools, 6 | wheel, 7 | six, 8 | }: 9 | buildPythonPackage rec { 10 | pname = "pyactiveresource"; 11 | version = "2.2.2"; 12 | pyproject = true; 13 | 14 | src = fetchFromGitHub { 15 | owner = "Shopify"; 16 | repo = "pyactiveresource"; 17 | # github errors on tag fetch: 18 | # the given path has multiple possibilities: #, # 19 | rev = "e609d844ebace603f74bc5f0a67e9eafe7fb25e1"; 20 | hash = "sha256-DvM8P+2LXKtDQ6wIPr25t5xPswLP1m7acglYibkz/A4="; 21 | }; 22 | 23 | nativeBuildInputs = [ 24 | setuptools 25 | wheel 26 | six 27 | ]; 28 | 29 | pythonImportsCheck = ["pyactiveresource"]; 30 | doCheck = false; 31 | 32 | meta = with lib; { 33 | description = ""; 34 | homepage = "https://github.com/Shopify/pyactiveresource"; 35 | changelog = "https://github.com/Shopify/pyactiveresource/blob/${src.rev}/CHANGELOG"; 36 | license = licenses.mit; 37 | maintainers = with maintainers; []; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/overlays/tools/frx.nix: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 The Standard Authors 2 | { 3 | lib, 4 | buildGoModule, 5 | installShellFiles, 6 | paisano-tui, 7 | description, 8 | version, 9 | }: 10 | buildGoModule rec { 11 | inherit version; 12 | pname = "frx"; 13 | meta = { 14 | inherit description; 15 | license = with lib.licenses; unlicense; 16 | homepage = "https://github.com/blaggacao/frappix"; 17 | }; 18 | 19 | src = paisano-tui + /src; 20 | 21 | vendorHash = "sha256-S1oPselqHRIPcqDSsvdIkCwu1siQGRDHOkxWtYwa+g4="; 22 | 23 | nativeBuildInputs = [installShellFiles]; 24 | 25 | postInstall = '' 26 | mv $out/bin/paisano $out/bin/${pname} 27 | 28 | installShellCompletion --cmd ${pname} \ 29 | --bash <($out/bin/${pname} _carapace bash) \ 30 | --fish <($out/bin/${pname} _carapace fish) \ 31 | --zsh <($out/bin/${pname} _carapace zsh) 32 | ''; 33 | 34 | ldflags = [ 35 | "-s" 36 | "-w" 37 | "-X main.buildVersion=${version}" 38 | "-X main.argv0=${pname}" 39 | "-X main.project=Frappix" 40 | "-X flake.registry=__std" 41 | "-X env.dotdir=.std" 42 | ]; 43 | } 44 | -------------------------------------------------------------------------------- /src/overlays/frappe/insights-0001-build-socket-port-is-reverse-proxied.patch: -------------------------------------------------------------------------------- 1 | From 63b850891010a984f7f83a912528503268da1984 Mon Sep 17 00:00:00 2001 2 | From: David 3 | Date: Sat, 23 Mar 2024 15:43:16 +0100 4 | Subject: [PATCH] build: socket port is reverse proxied 5 | 6 | --- 7 | frontend/src/socket.js | 5 +---- 8 | 1 file changed, 1 insertion(+), 4 deletions(-) 9 | 10 | diff --git a/frontend/src/socket.js b/frontend/src/socket.js 11 | index 06e947db..6255ee76 100644 12 | --- a/frontend/src/socket.js 13 | +++ b/frontend/src/socket.js 14 | @@ -1,12 +1,9 @@ 15 | import { io } from 'socket.io-client' 16 | -import { socketio_port } from '../../../../sites/common_site_config.json' 17 | 18 | export function initSocket() { 19 | let host = window.location.hostname 20 | let siteName = import.meta.env.DEV ? host : window.site_name 21 | - let port = window.location.port ? `:${socketio_port}` : '' 22 | - let protocol = port ? 'http' : 'https' 23 | - let url = `${protocol}://${host}${port}/${siteName}` 24 | + let url = `https://${host}/${siteName}` 25 | 26 | let socket = io(url, { 27 | withCredentials: true, 28 | -- 29 | 2.42.0 30 | 31 | -------------------------------------------------------------------------------- /src/overlays/frappe/print-designer.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | python, 8 | extractFrappeMeta, 9 | mkAssets, 10 | }: 11 | buildPythonPackage rec { 12 | inherit 13 | (extractFrappeMeta src) 14 | pname 15 | version 16 | format 17 | ; 18 | 19 | src = mkAssets appSources.print-designer; 20 | inherit (appSources.print-designer) passthru; 21 | 22 | nativeBuildInputs = [ 23 | pythonRelaxDepsHook 24 | flit-core 25 | ]; 26 | 27 | propagatedBuildInputs = with python.pkgs; [ 28 | pyqrcode 29 | pypng 30 | python-barcode 31 | ]; 32 | 33 | pythonRelaxDeps = [ 34 | ]; 35 | 36 | # would require frappe, but since frappe is almost certainly customized, 37 | # we don't include it here / TODO: decide if we may actually add it? 38 | # pythonImportsCheck = ["erpnext"]; 39 | 40 | meta = with lib; { 41 | description = "Frappe App to Design Print Formats using interactive UI."; 42 | homepage = "https://github.com/frappe/print_designer"; 43 | license = licenses.agpl3Only; 44 | maintainers = with maintainers; [blaggacao]; 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /src/overlays/python/uuid-utils.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchFromGitHub, 5 | cargo, 6 | rustPlatform, 7 | rustc, 8 | mkdocs, 9 | mkdocs-material, 10 | mypy, 11 | pytest, 12 | ruff, 13 | }: 14 | buildPythonPackage rec { 15 | pname = "uuid-utils"; 16 | version = "0.9.0"; 17 | pyproject = true; 18 | 19 | src = fetchFromGitHub { 20 | owner = "aminalaee"; 21 | repo = "uuid-utils"; 22 | rev = version; 23 | hash = "sha256-DIXE/enhTxRWRESaOsjLk706RypIpXUKE/4KZ5vU9Uc="; 24 | }; 25 | 26 | cargoDeps = rustPlatform.importCargoLock { 27 | lockFile = ./Cargo.lock; 28 | }; 29 | 30 | build-system = [ 31 | cargo 32 | rustPlatform.cargoSetupHook 33 | rustPlatform.maturinBuildHook 34 | rustc 35 | ]; 36 | 37 | dependencies = [ 38 | mkdocs 39 | mkdocs-material 40 | mypy 41 | pytest 42 | ruff 43 | ]; 44 | 45 | pythonImportsCheck = [ 46 | "uuid_utils" 47 | ]; 48 | 49 | meta = with lib; { 50 | description = "Python bindings to Rust UUID"; 51 | homepage = "https://github.com/aminalaee/uuid-utils"; 52 | license = licenses.bsd3; 53 | maintainers = with maintainers; []; 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /src/overlays/frappe/ecommerce-integrations.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | python, 8 | extractFrappeMeta, 9 | mkAssets, 10 | }: 11 | buildPythonPackage rec { 12 | inherit 13 | (extractFrappeMeta src) 14 | pname 15 | version 16 | format 17 | ; 18 | 19 | src = mkAssets appSources.ecommerce-integrations; 20 | inherit (appSources.ecommerce-integrations) passthru; 21 | 22 | nativeBuildInputs = [ 23 | pythonRelaxDepsHook 24 | flit-core 25 | ]; 26 | 27 | propagatedBuildInputs = with python.pkgs; [ 28 | shopify-python-api 29 | boto3 30 | ]; 31 | 32 | pythonRelaxDeps = [ 33 | "shopifyapi" 34 | "boto3" 35 | ]; 36 | 37 | # would require frappe, but since frappe is almost certainly customized, 38 | # we don't include it here / TODO: decide if we may actually add it? 39 | # pythonImportsCheck = ["erpnext"]; 40 | 41 | meta = with lib; { 42 | description = "Ecommerce integrations for ERPNext"; 43 | homepage = "https://github.com/frappe/ecommerce_integrations"; 44 | license = licenses.gpl3Only; 45 | maintainers = with maintainers; [blaggacao]; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /src/overlays/tools/fsjd.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | writers, 4 | fetchurl, 5 | python3, 6 | }: let 7 | fsjd = 8 | writers.writePython3Bin "fsjd" { 9 | flakeIgnore = ["E501" "W605" "F541" "W293" "E303"]; 10 | libraries = with python3.pkgs; [ 11 | rich 12 | json-source-map 13 | ]; 14 | } 15 | (fetchurl { 16 | url = "https://gist.githubusercontent.com/blaggacao/91a9f4988c7528e8c8a5513e530341ef/raw/3b8852858b92be76a6cad95b9a4542d69645d1d1/frappe_schema_json_diff.py"; 17 | hash = "sha256-qT/YEJ4TY80Fy9nLariSoFp05TQ25j4MC4E99XMTIig="; 18 | }); 19 | in 20 | lib.lazyDerivation { 21 | derivation = writers.writeBashBin "fsjd" '' 22 | case $1 in 23 | --git) 24 | shift 1 25 | path="$1" 26 | oldfile="$2" 27 | oldhex="$3" 28 | oldmode="$4" 29 | newfile="$5" 30 | newhex="$6" 31 | newmode="$7" 32 | ;; 33 | *) 34 | path="$2" 35 | oldfile="$1" 36 | newfile="$2" 37 | ;; 38 | esac 39 | exec ${fsjd}/bin/fsjd $path $oldfile $newfile 0 40 | ''; 41 | meta.description = "Frappe Schema JSON Differ"; 42 | } 43 | -------------------------------------------------------------------------------- /examples/templates/frappe/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "MY FRAPPIX"; 3 | 4 | outputs = { 5 | frappix, 6 | std, 7 | self, 8 | ... 9 | } @ inputs: 10 | std.growOn { 11 | inherit inputs; 12 | cellsFrom = std.incl ./. ["tools" "apps" "deploy"]; 13 | cellBlocks = with std.blockTypes; [ 14 | # apps 15 | (frappix.nvchecker "_pins") 16 | (pkgs "pkgs") 17 | 18 | # local 19 | (anything "config" // {cli = false;}) 20 | (devshells "shells") 21 | (frappix.frapper "tasks") 22 | ]; 23 | }; 24 | 25 | # try to stick with a relesed version for a while 26 | inputs.nixpkgs.url = "github:nixos/nixpkgs/release-24.11"; 27 | 28 | inputs = { 29 | frappix.url = "github:blaggacao/frappix"; 30 | std.follows = "frappix/std"; 31 | devshell.url = "github:numtide/devshell"; 32 | devshell.inputs.nixpkgs.follows = "nixpkgs"; 33 | nixago.url = "github:nix-community/nixago"; 34 | nixago.inputs.nixpkgs.follows = "nixpkgs"; 35 | nixago.inputs.nixago-exts.follows = ""; 36 | std.inputs = { 37 | nixpkgs.follows = "nixpkgs"; 38 | devshell.follows = "devshell"; 39 | nixago.follows = "nixago"; 40 | }; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /src/overlays/python/rauth.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchFromGitHub, 5 | fetchpatch, 6 | requests, 7 | pytestCheckHook, 8 | mock, 9 | pycrypto, 10 | }: 11 | buildPythonPackage rec { 12 | pname = "rauth"; 13 | version = "0.7.2"; 14 | format = "setuptools"; 15 | 16 | src = fetchFromGitHub { 17 | owner = "litl"; 18 | repo = "rauth"; 19 | rev = version; 20 | hash = "sha256-wRKZbxZCEfihOaJM8sk8438LE++KJWxdOGImpL1gHa4="; 21 | }; 22 | 23 | patches = [ 24 | (fetchpatch { 25 | # https://github.com/litl/rauth/pull/211 26 | name = "fix-pycrypdodome-replacement-for-pycrypto.patch"; 27 | url = "https://github.com/litl/rauth/commit/7fb3b7bf1a1869a52cf59ee3eb607d318e97265c.patch"; 28 | hash = "sha256-jiAIw+VQ2d/bkm2brqfY1RUrNGf+lsMPnoI91gGUS6o="; 29 | }) 30 | ]; 31 | 32 | propagatedBuildInputs = [requests]; 33 | doCheck = false; 34 | 35 | meta = with lib; { 36 | description = "Python library for OAuth 1.0/a, 2.0, and Ofly"; 37 | homepage = "https://github.com/litl/rauth"; 38 | changelog = "https://github.com/litl/rauth/blob/${src.rev}/CHANGELOG"; 39 | license = licenses.mit; 40 | maintainers = with maintainers; [blaggacao]; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /examples/templates/frappe/apps/pkgs.nix: -------------------------------------------------------------------------------- 1 | let 2 | inherit (inputs) nixpkgs frappix; 3 | inherit (cell) _pins; 4 | 5 | inject = final: prev: { 6 | pythonPackagesExtensions = 7 | prev.pythonPackagesExtensions 8 | ++ [ 9 | (pyFinal: pyPrev: { 10 | # extend the python package set with yet-unpackaged or 11 | # more up-to-date python dependencies 12 | }) 13 | ]; 14 | # extend the frappix package set 15 | frappix = prev.frappix.overrideScope (finalFrappix: prevFrappix: { 16 | # inject your pinned sources (if any) into the frappix build pipeline 17 | appSources = prevFrappix.appSources.overrideScope (_: _: _pins); 18 | # add custom apps that are not yet packaged by frappix 19 | # my-app = finalFrappix.callPackage ./my-app.nix {}; 20 | }); 21 | }; 22 | 23 | pkgs = import nixpkgs.path { 24 | # wkhtmltopdf 25 | config.permittedInsecurePackages = ["openssl-1.1.1w"]; 26 | config.allowUnfree = true; 27 | 28 | system = nixpkgs.system; 29 | 30 | overlays = [ 31 | frappix.libsOverlay 32 | frappix.toolsOverlay 33 | frappix.pythonOverlay 34 | frappix.frappeOverlay 35 | inject 36 | ]; 37 | }; 38 | in 39 | pkgs 40 | -------------------------------------------------------------------------------- /src/overlays/frappe/crm.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | # rembg, 8 | python, 9 | extractFrappeMeta, 10 | mkAssets, 11 | applyPatches, 12 | }: 13 | buildPythonPackage rec { 14 | inherit 15 | (extractFrappeMeta src) 16 | pname 17 | version 18 | format 19 | ; 20 | 21 | src = mkAssets (appSources.crm 22 | // { 23 | src = applyPatches { 24 | inherit (appSources.crm) src; 25 | name = "crm-prod"; 26 | patches = [ 27 | ./crm-0001-build-socket-port-is-reverse-proxied.patch 28 | ]; 29 | }; 30 | }); 31 | inherit (appSources.crm) passthru; 32 | 33 | nativeBuildInputs = [ 34 | pythonRelaxDepsHook 35 | flit-core 36 | ]; 37 | 38 | propagatedBuildInputs = with python.pkgs; [ 39 | twilio 40 | ]; 41 | 42 | pythonRelaxDeps = [ 43 | "twilio" 44 | ]; 45 | 46 | # pythonImportsCheck = ["crm"]; 47 | 48 | meta = with lib; { 49 | description = "Delightful, open-source, work communication tool for remote teams"; 50 | homepage = "https://github.com/frappe/crm"; 51 | license = licenses.agpl3Only; 52 | maintainers = with maintainers; [blaggacao]; 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /apps/sources/frappe-uds-current-user-v15.patch: -------------------------------------------------------------------------------- 1 | commit 35e8d5ee433a839852f5183c1186ae128e9fa860 2 | Author: David 3 | Date: Fri Oct 25 14:24:57 2024 +0200 4 | 5 | use current user as db root 6 | 7 | diff --git a/frappe/database/mariadb/setup_db.py b/frappe/database/mariadb/setup_db.py 8 | index 84380216b2..78cbb0801b 100644 9 | --- a/frappe/database/mariadb/setup_db.py 10 | +++ b/frappe/database/mariadb/setup_db.py 11 | @@ -123,7 +123,7 @@ def get_root_connection(root_login, root_password): 12 | 13 | if not frappe.local.flags.root_connection: 14 | if not root_login: 15 | - root_login = "root" 16 | + root_login = getpass.getuser() or "root" 17 | 18 | if not root_password: 19 | root_password = frappe.conf.get("root_password") or None 20 | diff --git a/frappe/installer.py b/frappe/installer.py 21 | index 9a64747cd1..3d76c01d8f 100644 22 | --- a/frappe/installer.py 23 | +++ b/frappe/installer.py 24 | @@ -147,11 +147,6 @@ def install_db( 25 | if not db_type: 26 | db_type = frappe.conf.db_type 27 | 28 | - if not root_login and db_type == "mariadb": 29 | - root_login = "root" 30 | - elif not root_login and db_type == "postgres": 31 | - root_login = "postgres" 32 | - 33 | make_conf( 34 | db_name, 35 | site_config=site_config, 36 | -------------------------------------------------------------------------------- /src/nixos/test-ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSzCCAjOgAwIBAgIIPU9J6u5X80AwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE 3 | AxMVbWluaWNhIHJvb3QgY2EgM2Q0ZjQ5MCAXDTI0MDMwODE1NTY0NloYDzIxMjQw 4 | MzA4MTU1NjQ2WjAgMR4wHAYDVQQDExVtaW5pY2Egcm9vdCBjYSAzZDRmNDkwggEi 5 | MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDz8UiJosJ8VQHmnrDfOeSU4fa6 6 | TvryujuyQ70OsqA3V244AIbcIMN5Nu093xtDNcv1qPy4xgHM98CVX2p07L31YoIQ 7 | 9DQHfiGoQzpJDxByDnEp+M2yYXRAH7/w85GZIdg7UM983t0sZJO3/Snu1IK8TCfk 8 | m87cvulYDUt2znWXSu2tGJLxbI6hp37B2moct3gznWr4KBy7xhKp3aAhH00Dto5L 9 | fQz5/yxjz46P0Am+y+bD07vESIgpT1eE3vqvp1dzjLtWuSVVru0GvWmYmbApXun+ 10 | lvbB7le8axlS0HaYo8nwLW0PaMMASVPsxT331DgFmpSY0RpOB89JGIqHIsnFAgMB 11 | AAGjgYYwgYMwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr 12 | BgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRhPUqoqdzKlGry 13 | SGLr8TCyyffC/TAfBgNVHSMEGDAWgBRhPUqoqdzKlGrySGLr8TCyyffC/TANBgkq 14 | hkiG9w0BAQsFAAOCAQEABefjwBrn2FbngcB5je9FluoPFDlENOaAciaOcjRCa+1D 15 | ZMwETGhlYGqObHU/4knXdOas+LZv48ow32KFLVm+bWJre7BM9yThSpQgjOg00rLc 16 | Cm80UKiFFdrD1G/ywfysefh81Hf+r0q49B+JnJJ0uKrM/NrasCMoiB+GjzFkOSox 17 | g4j25wZMrvZZ6ObdotRac/A3viyFYraaxL6TckRin0AZolSZoZ3xehr5lEixYDBp 18 | f2sXM9K6qgR7+ytEi/B76VDLaPMwn6n642Nk85qn/C3aahoBg4Cd+AS3lCfewsoJ 19 | 9/DYMsacMgvtWw8WoqisrZdSACzqmWgK9cgStcJ0og== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /src/nixos/test-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSTCCAjGgAwIBAgIIX1DmGMtxE90wDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE 3 | AxMVbWluaWNhIHJvb3QgY2EgM2Q0ZjQ5MB4XDTI0MDMwODE1NTY0N1oXDTI2MDQw 4 | NzE0NTY0N1owGjEYMBYGA1UEAwwPKi5mcngubG9jYWxob3N0MIIBIjANBgkqhkiG 5 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmE4gVR3zJPD6mEmzjFHXn/RxOxWVJmxkMiL0 6 | i4QooPjH+vI9LHuPiqTCv3Y4j4rtiYr7qUVTmBJb+hbonKq/aMKTcddtjEGNgh9r 7 | j18EvXQD8VeXATmXiMpjr85g5EoE40R0Do9KyJj+55bxUNUJcmKCntqWtIK1tjlL 8 | aehIBuqhBELmc6a/xEQkxE1bV4YK4UuklhRpDsSAmyRYnKqVL3SsFNv11Hu8eARE 9 | CaJpHID1FgDQLfRs38iZvmikXAZNehD8199lZdVaItKnspcEfPa3J3NSSb5BZ3aS 10 | cVS8j5XYjcuvcXYJdkBRv78eavAqADB8FG+aq4mFRNbGkKooXQIDAQABo4GMMIGJ 11 | MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw 12 | DAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRhPUqoqdzKlGrySGLr8TCyyffC/TAp 13 | BgNVHREEIjAggg8qLmZyeC5sb2NhbGhvc3SCDWZyeC5sb2NhbGhvc3QwDQYJKoZI 14 | hvcNAQELBQADggEBABXUAYN05W63+LFNgwqOX3LOOlJGRVvJQqlzgVMCGs5qbnd3 15 | n12IeTHowZNqZ8oYU6600IOxE4MydFD43xnB03Fx+qH8k5uJhq0tWBSN0shocNt4 16 | M2qRLAUstV3zSLijpb1vkJ90fS6Mwy0iQIA0laCYmG1N7OX1fDu4Udd5MccgYQoM 17 | TLKX1Lh5XqyTmN346lnYSamxiKr3EFJadi12jU8YSMi0UbudTxHIGQCjmkAR0WBj 18 | dAfbyI7fMNCFlFq+1t4KowQjF6DU2e5ZmnPUhLIwdF6ABmt5/4nLAwRVv80IliTc 19 | gx6leAzAsCsJLM0qKY+worleMBZPY8YsJRG/+7Y= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /src/Readme.md: -------------------------------------------------------------------------------- 1 | # Using Frappix 2 | 3 | This `./src` cell implements Frappix, Frappe-on-Nix. 4 | 5 | ## `./config.nix` 6 | 7 | The `config` block contains the Procfile specification to launch a Frappe development server. 8 | 9 | ## `./shell.nix` 10 | 11 | The `shell` block contains a `bench` devshell module to set up a fully functional local development environment. 12 | 13 | ## `./overlays/` & `./pkgs.nix` 14 | 15 | The `overlays` block, together with the `pkgs` block, provides all necessary extra packages and dependencies. 16 | These are python dependencies, binaries or helpers that are not yet available in Nixpkgs. 17 | 18 | It also contains packaging for: 19 | 20 | - `frappe` 21 | - `erpnext` 22 | - `insight` 23 | - `gameplan` 24 | - `ecommerce-integrations` 25 | - `payments` 26 | - `wiki` 27 | 28 | See the [overlays readme](./overlays/Readme.md) for tips on how to package Frappe apps for Frappix. 29 | 30 | ## `./nixos/` 31 | 32 | The `nixos` block contains a nixos server implementation to run (multiple) Frappe domains. 33 | 34 | See the [nixos readme](./nixos/Readme.md) for more details. 35 | 36 | ## `./tests.nix` 37 | 38 | The `tests` block implements the `frappe` unit test suite as NixOS tests run in a VM. 39 | 40 | Please refer to [`./tests.md`](./tests.md) for more details. 41 | -------------------------------------------------------------------------------- /src/overlays/frappe/gameplan/0000-build-socket-port-is-reverse-proxied.patch: -------------------------------------------------------------------------------- 1 | From 90e248d2db0598dfa6ece435f9a0097a4edaeb3e Mon Sep 17 00:00:00 2001 2 | From: David 3 | Date: Sat, 23 Mar 2024 15:07:57 +0100 4 | Subject: [PATCH] build: socket port is reverse proxied 5 | 6 | --- 7 | frontend/src/socket.js | 5 +---- 8 | 1 file changed, 1 insertion(+), 4 deletions(-) 9 | 10 | diff --git a/frontend/src/socket.js b/frontend/src/socket.js 11 | index 2fa64af..93b68be 100644 12 | --- a/frontend/src/socket.js 13 | +++ b/frontend/src/socket.js 14 | @@ -1,14 +1,11 @@ 15 | import { io } from 'socket.io-client' 16 | -import { socketio_port } from '../../../../sites/common_site_config.json' 17 | import { getCachedListResource } from 'frappe-ui/src/resources/listResource' 18 | import { getCachedResource } from 'frappe-ui/src/resources/resources' 19 | 20 | export function initSocket() { 21 | let host = window.location.hostname 22 | let siteName = window.site_name 23 | - let port = window.location.port ? `:${socketio_port}` : '' 24 | - let protocol = port ? 'http' : 'https' 25 | - let url = `${protocol}://${host}${port}/${siteName}` 26 | + let url = `https://${host}/${siteName}` 27 | 28 | let socket = io(url, { 29 | withCredentials: true, 30 | -- 31 | 2.42.0 32 | 33 | -------------------------------------------------------------------------------- /apps/sources/frappe-uds-current-user-develop.patch: -------------------------------------------------------------------------------- 1 | diff --git a/frappe/database/mariadb/setup_db.py b/frappe/database/mariadb/setup_db.py 2 | index 152d16c649..769b850970 100644 3 | --- a/frappe/database/mariadb/setup_db.py 4 | +++ b/frappe/database/mariadb/setup_db.py 5 | @@ -154,11 +154,11 @@ def check_compatible_versions(): 6 | 7 | def get_root_connection(): 8 | if not frappe.local.flags.root_connection: 9 | - from getpass import getpass 10 | + from getpass import getpass, getuser 11 | 12 | if not frappe.flags.root_login: 13 | frappe.flags.root_login = ( 14 | - frappe.conf.get("root_login") or input("Enter mysql super user [root]: ") or "root" 15 | + frappe.conf.get("root_login") or getuser() 16 | ) 17 | 18 | if not frappe.flags.root_password and not frappe.conf.db_socket: 19 | diff --git a/frappe/installer.py b/frappe/installer.py 20 | index 5c2f931b51..a82de85936 100644 21 | --- a/frappe/installer.py 22 | +++ b/frappe/installer.py 23 | @@ -143,11 +143,6 @@ def install_db( 24 | if not db_type: 25 | db_type = frappe.conf.db_type 26 | 27 | - if not root_login and db_type == "mariadb": 28 | - root_login = "root" 29 | - elif not root_login and db_type == "postgres": 30 | - root_login = "postgres" 31 | - 32 | make_conf( 33 | db_name, 34 | site_config=site_config, 35 | -------------------------------------------------------------------------------- /src/overlays/frappe/gameplan/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | # rembg, 8 | python, 9 | extractFrappeMeta, 10 | mkAssets, 11 | applyPatches, 12 | }: 13 | buildPythonPackage rec { 14 | inherit 15 | (extractFrappeMeta src) 16 | pname 17 | version 18 | format 19 | ; 20 | 21 | src = mkAssets (appSources.gameplan 22 | // { 23 | src = applyPatches { 24 | inherit (appSources.gameplan) src; 25 | name = "gameplan-prod"; 26 | patches = [ 27 | ./0000-build-socket-port-is-reverse-proxied.patch 28 | ]; 29 | }; 30 | }); 31 | inherit (appSources.gameplan) passthru; 32 | 33 | nativeBuildInputs = [ 34 | pythonRelaxDepsHook 35 | flit-core 36 | ]; 37 | 38 | propagatedBuildInputs = with python.pkgs; [ 39 | rembg 40 | ]; 41 | 42 | pythonRemoveDeps = [ 43 | "rembg" # TODO: package 44 | ]; 45 | 46 | # pythonImportsCheck = ["gameplan"]; 47 | 48 | meta = with lib; { 49 | description = "Delightful, open-source, work communication tool for remote teams"; 50 | homepage = "https://github.com/frappe/gameplan"; 51 | license = licenses.agpl3Only; 52 | maintainers = with maintainers; [blaggacao]; 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /src/overlays/frappe/payments.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | flit-core, 6 | pythonRelaxDepsHook, 7 | python, 8 | extractFrappeMeta, 9 | mkAssets, 10 | }: 11 | buildPythonPackage rec { 12 | inherit 13 | (extractFrappeMeta src) 14 | pname 15 | version 16 | format 17 | ; 18 | 19 | src = mkAssets appSources.payments; 20 | inherit (appSources.payments) passthru; 21 | 22 | nativeBuildInputs = [ 23 | pythonRelaxDepsHook 24 | flit-core 25 | ]; 26 | 27 | propagatedBuildInputs = with python.pkgs; [ 28 | braintree 29 | paytmchecksum 30 | pycryptodome 31 | razorpay 32 | stripe 33 | gocardless-pro 34 | ]; 35 | 36 | pythonRelaxDeps = [ 37 | "braintree" 38 | "pycryptodome" 39 | "stripe" 40 | "razorpay" 41 | "paytmchecksum" 42 | "gocardless-pro" 43 | ]; 44 | 45 | # would require frappe, but since frappe is almost certainly customized, 46 | # we don't include it here / TODO: decide if we may actually add it? 47 | # pythonImportsCheck = ["payments"]; 48 | 49 | meta = with lib; { 50 | description = "Payments app for frappe"; 51 | homepage = "https://github.com/frappe/payments.git"; 52 | license = licenses.mit; 53 | maintainers = with maintainers; []; 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /src/overlays/libs/redi-search/rl-test.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchFromGitHub, 5 | poetry-core, 6 | distro, 7 | setuptools, 8 | progressbar2, 9 | psutil, 10 | pytest, 11 | pytest-cov, 12 | redis, 13 | pythonRelaxDepsHook, 14 | }: 15 | buildPythonPackage rec { 16 | pname = "rl-test"; 17 | version = "0.7.13"; 18 | pyproject = true; 19 | 20 | src = fetchFromGitHub { 21 | owner = "RedisLabsModules"; 22 | repo = "RLTest"; 23 | rev = "v${version}"; 24 | hash = "sha256-I4334560n02ZL3SY1DH246REeeR8IvzbXXEzPckHaMA="; 25 | }; 26 | 27 | build-system = [ 28 | poetry-core 29 | pythonRelaxDepsHook 30 | ]; 31 | 32 | dependencies = [ 33 | distro 34 | progressbar2 35 | psutil 36 | pytest 37 | pytest-cov 38 | redis 39 | setuptools 40 | ]; 41 | pythonRelaxDeps = [ 42 | # - progressbar2==4.2 not satisfied by version 4.4.2 43 | "progressbar2" 44 | # - pytest<8.0,>=7.4 not satisfied by version 8.1.1 45 | "pytest" 46 | ]; 47 | 48 | pythonImportsCheck = [ 49 | "RLTest" 50 | ]; 51 | 52 | meta = with lib; { 53 | description = "Redis Labs Test Framework"; 54 | homepage = "https://github.com/RedisLabsModules/RLTest"; 55 | license = licenses.bsd3; 56 | maintainers = with maintainers; []; 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /src/overlays/frappe/insights.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | python, 8 | extractFrappeMeta, 9 | mkAssets, 10 | applyPatches, 11 | }: 12 | buildPythonPackage rec { 13 | inherit 14 | (extractFrappeMeta src) 15 | pname 16 | version 17 | format 18 | ; 19 | 20 | src = mkAssets (appSources.insights 21 | // { 22 | src = applyPatches { 23 | inherit (appSources.insights) src; 24 | name = "insights-prod"; 25 | patches = [ 26 | ./insights-0001-build-socket-port-is-reverse-proxied.patch 27 | ]; 28 | }; 29 | }); 30 | inherit (appSources.insights) passthru; 31 | 32 | nativeBuildInputs = [ 33 | pythonRelaxDepsHook 34 | flit-core 35 | ]; 36 | 37 | propagatedBuildInputs = with python.pkgs; [ 38 | pandas 39 | python-telegram-bot 40 | sqlalchemy 41 | ]; 42 | 43 | pythonImportsCheck = ["insights"]; 44 | 45 | pythonRelaxDeps = [ 46 | "python-telegram-bot" 47 | "SQLAlchemy" 48 | "pandas" 49 | ]; 50 | 51 | meta = with lib; { 52 | description = "Free and Open Source Data Analytics Tool for your Frappe Apps"; 53 | homepage = "https://github.com/frappe/insights"; 54 | license = licenses.agpl3Only; 55 | maintainers = with maintainers; [blaggacao]; 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /src/overlays/python/shopify-python-api.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | pythonRelaxDepsHook, 5 | fetchFromGitHub, 6 | setuptools, 7 | wheel, 8 | pyjwt, 9 | pyyaml, 10 | six, 11 | pyactiveresource, 12 | mock, 13 | }: 14 | buildPythonPackage rec { 15 | pname = "shopify-python-api"; 16 | version = "12.3.0"; 17 | pyproject = true; 18 | 19 | src = fetchFromGitHub { 20 | owner = "Shopify"; 21 | repo = "shopify_python_api"; 22 | rev = "v${version}"; 23 | hash = "sha256-VNURY+y2RHjJnUl2QmQSgNU6hOeAO5rQXbfkkSOZ+k8="; 24 | }; 25 | 26 | nativeBuildInputs = [ 27 | pythonRelaxDepsHook 28 | setuptools 29 | wheel 30 | ]; 31 | 32 | nativeCheckInputs = [ 33 | mock 34 | ]; 35 | 36 | propagatedBuildInputs = [ 37 | setuptools 38 | pyjwt 39 | pyyaml 40 | six 41 | pyactiveresource 42 | ]; 43 | 44 | pythonRelaxDeps = [ 45 | # "PyYAML" 46 | ]; 47 | 48 | pythonImportsCheck = ["shopify"]; 49 | doCheck = false; 50 | 51 | meta = with lib; { 52 | description = "ShopifyAPI library allows Python developers to programmatically access the admin section of stores"; 53 | homepage = "https://github.com/Shopify/shopify_python_api"; 54 | changelog = "https://github.com/Shopify/shopify_python_api/blob/${src.rev}/CHANGELOG"; 55 | license = licenses.mit; 56 | maintainers = with maintainers; []; 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /src/overlays/python/default.nix: -------------------------------------------------------------------------------- 1 | pyFinal: pyPrev: { 2 | # frappe dependencies 3 | barcodenumber = pyFinal.callPackage ./barcodenumber.nix {}; 4 | email-reply-parser = pyFinal.callPackage ./email-reply-parser.nix {}; 5 | traceback-with-variables = pyFinal.callPackage ./traceback-with-variables {}; 6 | uuid-utils = pyFinal.callPackage ./uuid-utils.nix {}; 7 | sql_metadata = pyFinal.callPackage ./sql_metadata.nix {}; 8 | premailer = pyFinal.callPackage ./premailer.nix {}; # not anymore in nixpkgs, see: https://github.com/NixOS/nixpkgs/pull/348580 9 | rauth = pyFinal.callPackage ./rauth.nix {}; # not anymore in nixpkgs, see: https://github.com/NixOS/nixpkgs/pull/330417 10 | 11 | # erpnext dependencies 12 | plaid-python = pyFinal.callPackage ./plaid-python.nix {}; # old version 13 | 14 | # payments dependencies 15 | razorpay = pyFinal.callPackage ./razorpay.nix {}; 16 | paytmchecksum = pyFinal.callPackage ./paytmchecksum.nix {}; 17 | 18 | # gameplan dependencies 19 | rembg = pyFinal.callPackage ./rembg.nix {}; 20 | 21 | # ecommerce-integrations dependencies 22 | shopify-python-api = pyFinal.callPackage ./shopify-python-api.nix {}; 23 | pyactiveresource = pyFinal.callPackage ./pyactiveresource.nix {}; 24 | 25 | # raven dependencies 26 | linkpreview = pyFinal.callPackage ./linkpreview.nix {}; 27 | 28 | # fjsd dependency 29 | json-source-map = pyFinal.callPackage ./json-source-map.nix {}; 30 | } 31 | -------------------------------------------------------------------------------- /src/overlays/frappe/crm-0001-build-socket-port-is-reverse-proxied.patch: -------------------------------------------------------------------------------- 1 | From 73836b57879bfe84b23cf4d9802ed9d583d5c57e Mon Sep 17 00:00:00 2001 2 | From: David 3 | Date: Sun, 16 Jun 2024 19:50:30 +0200 4 | Subject: [PATCH] build: socket port is reverse proxied 5 | 6 | --- 7 | frontend/src/socket.js | 7 ++----- 8 | 1 file changed, 2 insertions(+), 5 deletions(-) 9 | 10 | diff --git a/frontend/src/socket.js b/frontend/src/socket.js 11 | index 9a0c7d0..93b68be 100644 12 | --- a/frontend/src/socket.js 13 | +++ b/frontend/src/socket.js 14 | @@ -1,14 +1,11 @@ 15 | import { io } from 'socket.io-client' 16 | -import { socketio_port } from '../../../../sites/common_site_config.json' 17 | import { getCachedListResource } from 'frappe-ui/src/resources/listResource' 18 | import { getCachedResource } from 'frappe-ui/src/resources/resources' 19 | 20 | export function initSocket() { 21 | let host = window.location.hostname 22 | let siteName = window.site_name 23 | - let port = window.location.port ? `:${socketio_port}` : '' 24 | - let protocol = port ? 'http' : 'https' 25 | - let url = `${protocol}://${host}${port}/${siteName}` 26 | + let url = `https://${host}/${siteName}` 27 | 28 | let socket = io(url, { 29 | withCredentials: true, 30 | @@ -25,4 +22,4 @@ export function initSocket() { 31 | } 32 | }) 33 | return socket 34 | -} 35 | \ No newline at end of file 36 | +} 37 | -- 38 | 2.42.0 39 | 40 | -------------------------------------------------------------------------------- /src/vms.nix: -------------------------------------------------------------------------------- 1 | let 2 | inherit (inputs.std.inputs) microvm; 3 | inherit (inputs) nixpkgs; 4 | inherit (cell) pkgs nixos; 5 | eval = module: 6 | import (nixpkgs + /nixos/lib/eval-config.nix) { 7 | inherit (nixpkgs) system; 8 | modules = [module]; 9 | }; 10 | in { 11 | default = eval ({config, ...}: { 12 | imports = [ 13 | microvm.nixosModules.microvm 14 | nixos.frappix 15 | nixos.testrig 16 | ]; 17 | nixpkgs = {inherit pkgs;}; 18 | # hardware.opengl.enable = true; 19 | users.allowNoPasswordLogin = true; 20 | microvm = { 21 | hypervisor = "qemu"; 22 | graphics.enable = false; 23 | vcpu = 4; 24 | mem = 4096; 25 | # forwardPorts = [ 26 | # { 27 | # guest.port = 80; 28 | # host.port = 8080; 29 | # } 30 | # { 31 | # guest.port = 443; 32 | # host.port = 4433; 33 | # } 34 | # ]; 35 | # share the host's /nix/store if the hypervisor can do 9p 36 | shares = [ 37 | { 38 | tag = "ro-store"; 39 | source = "/nix/store"; 40 | mountPoint = "/nix/.ro-store"; 41 | # proto = "virtiofs"; 42 | } 43 | ]; 44 | writableStoreOverlay = "/nix/.rw-store"; 45 | volumes = [ 46 | { 47 | image = "nix-store-overlay.img"; 48 | mountPoint = config.microvm.writableStoreOverlay; 49 | size = 2048; 50 | } 51 | ]; 52 | }; 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /src/overlays/python/traceback-with-variables/default.nix: -------------------------------------------------------------------------------- 1 | # https://github.com/NixOS/nixpkgs/pull/244733 2 | { 3 | lib, 4 | buildPythonPackage, 5 | fetchFromGitHub, 6 | pytestCheckHook, 7 | pytest-cov, 8 | ipython, 9 | pythonAtLeast, 10 | }: 11 | buildPythonPackage rec { 12 | pname = "traceback-with-variables"; 13 | version = "2.0.4"; 14 | format = "setuptools"; 15 | # disabled = pythonAtLeast "3.11"; 16 | 17 | src = fetchFromGitHub { 18 | owner = "andy-landy"; 19 | repo = "traceback_with_variables"; 20 | rev = "v${version}"; 21 | hash = "sha256-XxmWmGIwF+hd256XA8nWLxF5UTwZngL+0kQYfmsfYAA="; 22 | }; 23 | 24 | patches = [ 25 | ./01-fix-test-ouput.patch 26 | ]; 27 | 28 | pythonImportsCheck = ["traceback_with_variables"]; 29 | doCheck = false; 30 | 31 | # warns about distutils removal in python 3.12 32 | # would modify executable output and thereby fail tests 33 | # can't use pytestFlagsArray as tests are a secondary command invokation 34 | PYTHONWARNINGS = "ignore::DeprecationWarning"; 35 | 36 | nativeCheckInputs = [ 37 | pytestCheckHook 38 | ipython 39 | pytest-cov 40 | ]; 41 | 42 | meta = with lib; { 43 | description = "Adds local variables to python traceback"; 44 | homepage = "https://github.com/andy-landy/traceback_with_variables"; 45 | changelog = "https://github.com/andy-landy/traceback_with_variables/blob/${src.rev}/CHANGELOG.md"; 46 | license = licenses.mit; 47 | maintainers = with maintainers; [blaggacao]; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/overlays/frappe/erpnext.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | python, 8 | extractFrappeMeta, 9 | mkAssets, 10 | }: 11 | buildPythonPackage rec { 12 | inherit 13 | (extractFrappeMeta src) 14 | pname 15 | version 16 | format 17 | ; 18 | 19 | src = mkAssets appSources.erpnext; 20 | inherit (appSources.erpnext) passthru; 21 | 22 | nativeBuildInputs = [ 23 | pythonRelaxDepsHook 24 | flit-core 25 | ]; 26 | 27 | propagatedBuildInputs = with python.pkgs; [ 28 | barcodenumber 29 | googlemaps 30 | holidays 31 | plaid-python 32 | pycountry 33 | pypng 34 | python-youtube 35 | rapidfuzz 36 | tweepy 37 | unidecode 38 | ]; 39 | 40 | pythonRelaxDeps = [ 41 | # - pycountry~=22.3.5 not satisfied by version 23.12.11 42 | "pycountry" 43 | # - rapidfuzz~=2.15.0 not satisfied by version 3.9.1 44 | "rapidfuzz" 45 | # - python-youtube~=0.8.0 not satisfied by version 0.9.4 46 | "python-youtube" 47 | ]; 48 | 49 | # would require frappe, but since frappe is almost certainly customized, 50 | # we don't include it here / TODO: decide if we may actually add it? 51 | # pythonImportsCheck = ["erpnext"]; 52 | 53 | meta = with lib; { 54 | description = "Free and Open Source Enterprise Resource Planning (ERP"; 55 | homepage = "https://github.com/frappe/erpnext"; 56 | license = licenses.gpl3Only; 57 | maintainers = with maintainers; [blaggacao]; 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /local/shells.nix: -------------------------------------------------------------------------------- 1 | /* 2 | This file holds reproducible shells with commands in them. 3 | 4 | They conveniently also generate config files in their startup hook. 5 | */ 6 | let 7 | inherit (cell) config; 8 | inherit (inputs.std.std) cli; 9 | inherit (inputs.std.lib) dev cfg; 10 | pkgs = import inputs.nixpkgs { 11 | inherit (inputs.nixpkgs) system; 12 | overlays = [ 13 | inputs.cells.src.overlays.tools 14 | ]; 15 | }; 16 | in { 17 | # Tool Homepage: https://numtide.github.io/devshell/ 18 | default = 19 | (dev.mkShell { 20 | name = "Frappix Shell"; 21 | 22 | # Tool Homepage: https://nix-community.github.io/nixago/ 23 | # This is Standard's devshell integration. 24 | # It runs the startup hook when entering the shell. 25 | nixago = [ 26 | (dev.mkNixago cfg.conform) 27 | (dev.mkNixago cfg.treefmt config.treefmt) 28 | (dev.mkNixago cfg.editorconfig config.editorconfig) 29 | (dev.mkNixago cfg.lefthook config.lefthook) 30 | (dev.mkNixago cfg.mdbook config.mdbook) 31 | ]; 32 | 33 | commands = [ 34 | {package = cli.std;} 35 | {package = pkgs.nvfetcher;} 36 | {package = pkgs.nvchecker-nix;} 37 | ]; 38 | }) 39 | // {meta.description = "Development environment for this repository";}; 40 | book = 41 | (dev.mkShell { 42 | name = "Frappix Book Shell"; 43 | nixago = [(dev.mkNixago cfg.mdbook config.mdbook)]; 44 | }) 45 | // {meta.description = "Book development & rendering environment for this repository";}; 46 | } 47 | -------------------------------------------------------------------------------- /src/overlays/tools/default.nix: -------------------------------------------------------------------------------- 1 | inputs: final: prev: { 2 | nvchecker-nix = final.python3.pkgs.callPackage ./nvchecker.nix {}; 3 | # special (optional) yarn build tooling for frappe 4 | mkAssets = final.callPackage ./mkAssets.nix {}; 5 | # consolidated site assets 6 | mkSiteAssets = final.callPackage ./mkSiteAssets.nix {}; 7 | 8 | fsjd = final.callPackage ./fsjd.nix {}; 9 | frx = final.callPackage ./frx.nix { 10 | version = inputs.nixpkgs.lib.fileContents (inputs.self + /VERSION); 11 | inherit (inputs.std.inputs) paisano-tui; 12 | inherit (import (inputs.self + /flake.nix)) description; 13 | }; 14 | extractFrappeMeta = src: let 15 | inherit (builtins) match head replaceStrings readFile fromTOML; 16 | pyproject = fromTOML (readFile (src + /pyproject.toml)); 17 | format = "pyproject"; 18 | pname = pyproject.project.name; 19 | version = let 20 | init = readFile (src + "/${pname}/__init__.py"); 21 | m = match ''.*__version__ = ["|']([^("|')]+).*'' init; 22 | op = v: 23 | replaceStrings ["-"] ["."] ( 24 | if prev.lib.hasSuffix "dev" v 25 | then v + "0" 26 | else v 27 | ); 28 | in 29 | op ( 30 | if pyproject.project ? version 31 | then pyproject.project.version 32 | else (head m) 33 | ); 34 | in { 35 | inherit format version pname; 36 | }; 37 | bench = final.callPackage ./bench.nix {}; 38 | apps = final.callPackage ./apps.nix {}; 39 | start-mariadb-for-frappe = final.callPackage ./start-mariadb-for-frappe.nix {}; 40 | analyze-prs = final.callPackage ./analyze-prs.nix {}; 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/std.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | workflow_dispatch: 9 | 10 | permissions: 11 | contents: read 12 | id-token: write 13 | 14 | concurrency: 15 | group: std-${{ github.workflow }}-${{ github.ref }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | discover: 20 | outputs: 21 | hits: ${{ steps.discovery.outputs.hits }} 22 | 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v3 26 | - uses: nixbuild/nix-quick-install-action@v25 27 | - uses: divnix/std-action/discover@main 28 | id: discovery 29 | 30 | oci-images: 31 | env: 32 | REGISTRY: ghcr.io 33 | IMAGE_NAME: ${{ github.repository }} 34 | permissions: 35 | contents: read 36 | packages: write 37 | attestations: write 38 | id-token: write 39 | needs: [discover] 40 | if: fromJSON(needs.discover.outputs.hits).oci-images.publish != '{}' 41 | strategy: 42 | matrix: 43 | target: ${{ fromJSON(needs.discover.outputs.hits).oci-images.publish }} 44 | name: ${{ matrix.target.jobName }} 45 | runs-on: ubuntu-latest 46 | steps: 47 | - uses: nixbuild/nix-quick-install-action@v25 48 | - uses: DeterminateSystems/magic-nix-cache-action@main 49 | - name: Log in to the Container registry 50 | uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 51 | with: 52 | registry: ${{ env.REGISTRY }} 53 | username: ${{ github.actor }} 54 | password: ${{ secrets.GITHUB_TOKEN }} 55 | - uses: divnix/std-action/run@main 56 | -------------------------------------------------------------------------------- /src/overlays/Readme.md: -------------------------------------------------------------------------------- 1 | # Package Frappe App 2 | 3 | Ensure the app has a `pyproject.toml`. 4 | If it has not, submit a PR according to [this change to the app template](https://github.com/frappe/frappe/pull/21704). 5 | 6 | 0. Inside this folder .. 7 | 1. Run `nix run github:nix-community/nix-init -- --url https://github.com/frappe/` 8 | 2. Follow instructions (choose as path `.nix`) 9 | 3. Select `buildPythonPackage` as packaging method 10 | 4. Add the new package to `default.nix` 11 | 12 | If dependencies are missing, you need to package them, too. 13 | 14 | #### Example 15 | 16 | ```console 17 | ❯ nix run github:nix-community/nix-init -- --url https://github.com/frappe/erpnext 18 | Enter output path (defaults to current directory) 19 | ❯ erpnext.nix 20 | Enter tag or revision (defaults to v14.31.3) 21 | ❯ develop 22 | Enter version 23 | ❯ develop 24 | Enter pname 25 | ❯ erpnext 26 | How should this package be built? 27 | ❯ 1 - buildPythonPackage - pyproject 28 | ``` 29 | 30 | ## Passthru contracts 31 | 32 | In order to account for some of the peculiarities of the frappé framework, the following passthru attributes are required: 33 | 34 | - `packages` 35 | - `test-dependencies` 36 | - `assets` 37 | 38 | They are for example consumed by the NixOS, shell or testing modules. 39 | 40 | ```nix 41 | passthru = rec { 42 | # made available to the development and runtime environment 43 | packages = [ 44 | mysql 45 | restic 46 | wkhtmltopdf-bin 47 | ]; 48 | # installed into the test environment (vm) 49 | test-dependencies = with python.pkgs; [ 50 | faker 51 | hypothesis 52 | responses 53 | ]; 54 | }; 55 | ``` 56 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yaml: -------------------------------------------------------------------------------- 1 | name: github pages 2 | 3 | on: 4 | # Runs on pushes targeting the default branch 5 | push: 6 | branches: ["main"] 7 | 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | 11 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 12 | permissions: 13 | contents: read 14 | pages: write 15 | id-token: write 16 | 17 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 18 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: false 22 | 23 | jobs: 24 | build: 25 | runs-on: ubuntu-latest 26 | concurrency: 27 | group: ${{ github.workflow }}-${{ github.ref }} 28 | steps: 29 | - uses: actions/checkout@v4 30 | 31 | - name: Install Nix 32 | uses: nixbuild/nix-quick-install-action@v25 33 | 34 | - name: Setup Pages 35 | id: pages 36 | uses: actions/configure-pages@v4 37 | 38 | - name: Build with MDBook from Book Shell 39 | run: nix develop .\#x86_64-linux.local.shells.book -c mdbook build ./. 40 | 41 | - name: Upload artifact 42 | uses: actions/upload-pages-artifact@v3 43 | with: 44 | path: ./docs/build/html 45 | 46 | # Deployment job 47 | deploy: 48 | environment: 49 | name: github-pages 50 | url: ${{ steps.deployment.outputs.page_url }} 51 | runs-on: ubuntu-latest 52 | needs: build 53 | steps: 54 | - name: Deploy to GitHub Pages 55 | id: deployment 56 | uses: actions/deploy-pages@v4 57 | -------------------------------------------------------------------------------- /src/nixos/test-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAmE4gVR3zJPD6mEmzjFHXn/RxOxWVJmxkMiL0i4QooPjH+vI9 3 | LHuPiqTCv3Y4j4rtiYr7qUVTmBJb+hbonKq/aMKTcddtjEGNgh9rj18EvXQD8VeX 4 | ATmXiMpjr85g5EoE40R0Do9KyJj+55bxUNUJcmKCntqWtIK1tjlLaehIBuqhBELm 5 | c6a/xEQkxE1bV4YK4UuklhRpDsSAmyRYnKqVL3SsFNv11Hu8eARECaJpHID1FgDQ 6 | LfRs38iZvmikXAZNehD8199lZdVaItKnspcEfPa3J3NSSb5BZ3aScVS8j5XYjcuv 7 | cXYJdkBRv78eavAqADB8FG+aq4mFRNbGkKooXQIDAQABAoIBADODSSBAzvoRn1Be 8 | rSGqlLl/HcUUGawzQPhMJlYBzxQS0OCpidM/v17vNwc23w59uLWqkk/AKPPoUb+W 9 | e/pxLegq11/Lszua+FeodOK7Colhcevw6hv59KzJd0oBDXhpKJoNjwtVn7+VL7H4 10 | tYnXZCiR9QfxesN26irF2iHp9GKR92SDYOe9RD4YKZgIU/KzOleX5IIJSPbTPn6i 11 | Lh4iRz5IthDwRhoB7yuJ2h2AwNOBRcVGWvyHXL2FBDI8CKClK6xYf1sLFckIqrd0 12 | 8p8FXtXM+exO55h/G4HqptkIh2+nKdYy0IKuwC6eOlCZdNjx6aHMMXCjZ1qgu7Mn 13 | GwAnGOkCgYEAwP/tTNurTM1n3fVKriJDsqrwusiBU86WtsQkBEqmCH1+T4LF6zGj 14 | fT3cofd0BgtYWkW0WYU5549eGLkQxGX5QBJwQA7Ozt++uDBGK6cePTxn2EHf712/ 15 | aFxwsYr4hPU9AdAdq/fFoNekju+MUIs+C4U6ojx0837wdaeuG7D2zwcCgYEAygWM 16 | uDWUtRo+GiJN6I8lCzFRJDhExIshggc5GL7yCCZbHOpXYAEzkIot2b7mu1ilqwW/ 17 | PJRUIkIBYuLU36csEeQ4CSGMwXB2iksQ3F2cJMmOnqsUtzcIwctQzQ/aKuWMclbi 18 | WLD44a+O1pNzw22+DeYjniXPpNFbqVvCBChp0HsCgYB1TplTr+kso2TQejlMIjN3 19 | s4LiZOCGqfjdWdZybVUBsBVICrp1vBQdGa6zG47/5YFsTRXTm7CYWIHfEQ1p8nlP 20 | QmXL6bQ19bUciur7uXYdzktoHJIaEac3rYgpwchQOCc+pNqEHfOXUbsJzfxBMIEj 21 | y3TaC1kibzOEr8iZuDQrnQKBgQCt3MzYlDRhEC62KyPFq7wDv/PHKi30wJCb6T94 22 | TozZ+ribUArWcvI/yMvhA+xq+8XIQ+/rYPRvb0LmKbVurd69nx2irh8HM5SxPB1M 23 | qbuB5X06jJ4Nd+2vax0k/imSlW+jz6aJEfV/talGfiw42q+gIpowtvXXMN6kCHYX 24 | QfifFQKBgQCeJ/Va1DpCqVIHEoWgzFvQsziyuLrZFeSddAXGMBby0XPjTXuUma4d 25 | b06yRBcZEUFKF9Akc2L9r8ddWIwPqdqDyDdKUWJ9al5XLpykKIfx10zNxGN2Gi08 26 | wfZbXvnw0BSk7WFRvUqVbFufdTWDJpSaON1fZrLCTtlqZncR+Ayw4g== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /src/overlays/tools/bench.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | writers, 4 | }: 5 | lib.lazyDerivation { 6 | derivation = let 7 | # Note: we need python from the bench viratualenv 8 | # these scripts implement the hand off where 9 | # we abandon the strictness and reproducibility 10 | # of Nix and trust the bench venv 11 | writeVenvPythonBin = name: 12 | writers.makeScriptWriter { 13 | # when inside venv, resolves to its python 14 | interpreter = "/usr/bin/env python"; 15 | } "/bin/${name}"; 16 | in 17 | writeVenvPythonBin "bench" '' 18 | import os 19 | import sys 20 | import click 21 | import json 22 | import warnings 23 | import frappe 24 | import frappe.utils.bench_helper 25 | 26 | site_root = os.getenv('FRAPPE_SITES_PATH') 27 | skipped_commands = json.loads(os.getenv('FRAPPE_DISABLED_COMMANDS', "[]")) 28 | 29 | if not site_root: 30 | raise Exception('FRAPPE_SITES_PATH env variable must be set!') 31 | 32 | os.chdir(site_root) 33 | 34 | if len(sys.argv) > 1 and sys.argv[1] != "frappe": 35 | sys.argv.insert(1,"frappe") 36 | 37 | if __name__ == "__main__": 38 | if not frappe._dev_server: 39 | warnings.simplefilter("ignore") 40 | commands = {} 41 | for app in frappe.utils.bench_helper.get_apps(): 42 | commands[app] = frappe.utils.bench_helper.get_app_group(app) 43 | if not commands[app]: 44 | continue 45 | for n, cmd in commands[app].commands.items(): 46 | if n in skipped_commands: 47 | cmd.hidden = True 48 | click.Group(commands=commands)(prog_name="bench") 49 | ''; 50 | meta.description = "Run bench frappe CLI commands"; 51 | } 52 | -------------------------------------------------------------------------------- /docs/install.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | To initialize a Frappix project (a more reproducible "bench"), you may use the guided install script with: 4 | 5 | > [!IMPORTANT] 6 | > 7 | > `git` must be configured in your system (email / name). 8 | 9 | ```console 10 | bash <(curl -L https://blaggacao.github.io/frappix/install) frappe myproject 11 | ``` 12 | 13 | This script does two things: 14 | 15 | - ensure system dependencies are in place 16 | - guide you through the project setup 17 | 18 | > [!TIP] 19 | > 20 | > `frappe`, the first argument to the script represents the template to use. 21 | > For an overview over the available templates, run: 22 | > 23 | > ```shell 24 | > nix flake show github:blaggacao/frappix 25 | > ``` 26 | > 27 | > You'll already need to have nix installed to run this command. 28 | 29 | ## System dependencies 30 | 31 | If not already present on your system, this script will ensure the minimal dependencies are installed: 32 | 33 | - Nix: _global package manager & language interpreter_ 34 | - Direnv: _tool to manage environments per folder_ 35 | - Nom: _nix output monitor for for better display_ 36 | - Frappix Tool: _runs repository tasks_ 37 | 38 | You can inspect the bill of material of this install script in [its source](https://github.com/paisano-nix/onboarding/blob/main/install). 39 | 40 | ## Guided Install 41 | 42 | It will guide you through the setup process for a Frappix project. 43 | 44 | ## Enable Extra Repository Tooling 45 | 46 | The extra tooling provides: 47 | 48 | - Formatter support 49 | - Commit lint support 50 | - Documentation support 51 | - Editorconfig template 52 | 53 | To enable it, change the following value in `tools/shells.nix`: 54 | 55 | ```diff 56 | { 57 | - bench.enableExtraProjectTools = false; 58 | + bench.enableExtraProjectTools = true; 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /src/overlays/tools/mkAssets.nix: -------------------------------------------------------------------------------- 1 | # adopted from: https://git.pub.solar/axeman/erpnext-nix/src/branch/main/node/mk-app.nix 2 | { 3 | runCommand, 4 | path, 5 | nodejs_20, 6 | yarn, 7 | nodePackages, 8 | emptyFile, 9 | yarn2nix-moretea, 10 | callPackage, 11 | lib, 12 | stdenv, 13 | }: let 14 | inherit (yarn2nix-moretea) mkYarnNix; 15 | in 16 | { 17 | pname, 18 | src, 19 | version, 20 | ... 21 | }: let 22 | yarnLock = "${src}/yarn.lock"; 23 | yarnOfflineCache = 24 | (callPackage (mkYarnNix { 25 | yarnLock = 26 | if builtins.pathExists yarnLock 27 | then yarnLock 28 | else emptyFile; 29 | }) {}) 30 | .offline_cache; 31 | hasLock = builtins.pathExists yarnLock; 32 | pjson = lib.importJSON (src + /package.json); 33 | runBuild = pjson ? scripts && pjson.scripts ? build && pname != "frappe"; 34 | in 35 | stdenv.mkDerivation { 36 | pname = pname + "_"; 37 | inherit src version; 38 | nativeBuildInputs = [ 39 | nodejs_20 40 | (yarn.overrideAttrs {withNode = false;}) 41 | yarn2nix-moretea.fixup_yarn_lock 42 | ]; 43 | configurePhase = '' 44 | export HOME=$(mktemp -d) 45 | ''; 46 | buildPhase = 47 | lib.optionalString hasLock '' 48 | yarn config --offline set yarn-offline-mirror ${yarnOfflineCache} 49 | fixup_yarn_lock yarn.lock 50 | yarn install --offline \ 51 | --frozen-lockfile \ 52 | --ignore-engines --ignore-scripts 53 | patchShebangs . 54 | '' 55 | + lib.optionalString (hasLock && runBuild) '' 56 | yarn --offline --frozen-lockfile --ignore-engines build 57 | ''; 58 | 59 | installPhase = '' 60 | mkdir -p $out 61 | cp -R . $out 62 | ''; 63 | } 64 | -------------------------------------------------------------------------------- /apps/sources.nix: -------------------------------------------------------------------------------- 1 | let 2 | inherit (builtins) readDir; 3 | inherit (inputs.nixpkgs) lib applyPatches substituteAll; 4 | 5 | fileIsNix = basename: type: type == "regular" && lib.hasSuffix ".nix" basename; 6 | 7 | loadPath = path: name: _: import (lib.path.append path name); 8 | 9 | sourceDirectoryEntries = path: lib.mapAttrs (loadPath path) (lib.filterAttrs fileIsNix (readDir path)); 10 | 11 | sanitizeKey = name: attrs: lib.nameValuePair (lib.removeSuffix ".nix" name) attrs; 12 | 13 | applyInputPatches = name: attrs: 14 | { 15 | frappe = let 16 | workdirsrc = applyPatches { 17 | name = "frappe-source-1"; 18 | inherit (attrs) src; 19 | # this patch is needs to be present in all source trees, 20 | # such as the next one used for the assets below 21 | patches = [ 22 | # This mariadb has passwordless root access 23 | # for the current user 24 | ./sources/frappe-uds-current-user-v15.patch 25 | # ./sources/frappe-uds-current-user-develop.patch 26 | ]; 27 | }; 28 | deploysrc = applyPatches { 29 | name = "frappe-source-2"; 30 | src = workdirsrc; 31 | patches = [ 32 | # make the relative path to the generator script absolute 33 | # but reference the already patched version to work with uds 34 | (substituteAll { 35 | src = ./sources/frappe-website-generator.patch; 36 | frappe = workdirsrc; 37 | }) 38 | ]; 39 | }; 40 | in 41 | attrs 42 | // { 43 | src = deploysrc; 44 | passthru = (attrs.passthru or {}) // {inherit workdirsrc;}; 45 | }; 46 | } 47 | .${name} 48 | or attrs; 49 | in 50 | lib.mapAttrs applyInputPatches (lib.mapAttrs' sanitizeKey (sourceDirectoryEntries ./sources)) 51 | -------------------------------------------------------------------------------- /src/overlays/tools/nvchecker.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | platformdirs, 4 | buildPythonPackage, 5 | docutils, 6 | fetchFromGitHub, 7 | flaky, 8 | installShellFiles, 9 | pycurl, 10 | pytest-asyncio, 11 | pytest-httpbin, 12 | pytestCheckHook, 13 | pythonOlder, 14 | setuptools, 15 | structlog, 16 | tomli, 17 | tornado, 18 | }: 19 | buildPythonPackage rec { 20 | pname = "nvchecker"; 21 | version = "2.17dev-nix2"; 22 | pyproject = true; 23 | 24 | disabled = pythonOlder "3.8"; 25 | 26 | src = fetchFromGitHub { 27 | owner = "blaggacao"; 28 | repo = pname; 29 | rev = "v${version}"; 30 | hash = "sha256-EOOUS9k/YPe+Y6eaTLxwCuI0MDR/z4WvQ7ARAuU3Q+w="; 31 | }; 32 | 33 | nativeBuildInputs = [ 34 | setuptools 35 | docutils 36 | installShellFiles 37 | ]; 38 | 39 | propagatedBuildInputs = 40 | [ 41 | structlog 42 | platformdirs 43 | tornado 44 | pycurl 45 | ] 46 | ++ lib.optionals (pythonOlder "3.11") [ 47 | tomli 48 | ]; 49 | 50 | __darwinAllowLocalNetworking = true; 51 | doCheck = false; 52 | 53 | nativeCheckInputs = [ 54 | flaky 55 | pytest-asyncio 56 | pytest-httpbin 57 | pytestCheckHook 58 | ]; 59 | 60 | postBuild = '' 61 | patchShebangs docs/myrst2man.py 62 | make -C docs man 63 | ''; 64 | 65 | postInstall = '' 66 | installManPage docs/_build/man/nvchecker.1 67 | ''; 68 | 69 | pythonImportsCheck = [ 70 | "nvchecker" 71 | ]; 72 | 73 | pytestFlagsArray = [ 74 | "-m 'not needs_net'" 75 | ]; 76 | 77 | meta = with lib; { 78 | description = "New version checker for software (with nix writer)"; 79 | homepage = "https://github.com/lilydjwg/nvchecker"; 80 | changelog = "https://github.com/lilydjwg/nvchecker/releases/tag/v${version}"; 81 | license = licenses.mit; 82 | maintainers = with maintainers; [marsam]; 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /src/overlays/frappe/drive/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | appSources, 3 | lib, 4 | buildPythonPackage, 5 | pythonRelaxDepsHook, 6 | flit-core, 7 | python, 8 | extractFrappeMeta, 9 | mkAssets, 10 | applyPatches, 11 | fetchpatch, 12 | }: 13 | buildPythonPackage rec { 14 | inherit 15 | (extractFrappeMeta src) 16 | pname 17 | version 18 | format 19 | ; 20 | 21 | src = mkAssets (appSources.drive 22 | // { 23 | src = applyPatches { 24 | inherit (appSources.drive) src; 25 | name = "drive"; # this is a constant consumed by frontend/package.json's copy-html-entry 26 | patches = [ 27 | (fetchpatch { 28 | url = "https://patch-diff.githubusercontent.com/raw/frappe/drive/pull/231.patch"; 29 | hash = "sha256-hgiVnxqUOFE796hnv6dinPbaUKkB9MgRhj4IqMV6vhI="; 30 | }) 31 | (fetchpatch { 32 | url = "https://patch-diff.githubusercontent.com/raw/frappe/drive/pull/232.patch"; 33 | hash = "sha256-WQQNey0Nos3q7pjy0cr2abpo00gDQ9baPGnVXT9h5qU="; 34 | }) 35 | ]; 36 | }; 37 | }); 38 | inherit (appSources.drive) passthru; 39 | 40 | nativeBuildInputs = [ 41 | pythonRelaxDepsHook 42 | flit-core 43 | ]; 44 | 45 | propagatedBuildInputs = with python.pkgs; [ 46 | pillow 47 | opencv4 # opencv-python-headless 48 | python-magic 49 | ]; 50 | 51 | pythonRelaxDeps = [ 52 | ]; 53 | pythonRemoveDeps = [ 54 | "opencv-python-headless" 55 | ]; 56 | 57 | # would require frappe, but since frappe is almost certainly customized, 58 | # we don't include it here / TODO: decide if we may actually add it? 59 | # pythonImportsCheck = ["erpnext"]; 60 | 61 | meta = with lib; { 62 | description = "An easy to use, document sharing and management solution."; 63 | homepage = "https://github.com/frappe/drive"; 64 | license = licenses.agpl3Only; 65 | maintainers = with maintainers; [blaggacao]; 66 | }; 67 | } 68 | -------------------------------------------------------------------------------- /src/jobs.nix: -------------------------------------------------------------------------------- 1 | let 2 | inherit (inputs.nixpkgs.writers) writeBashBin; 3 | in { 4 | new-site = 5 | (writeBashBin "new-site.sh" '' 6 | start-mariadb-for-frappe & 7 | MARIA_PID=$! 8 | trap "kill -SIGTERM $MARIA_PID && wait $MARIA_PID" EXIT 9 | 10 | while ! mariadb-admin ping --silent; do 11 | echo "Waiting for MariaDB to start..." 12 | sleep 1 13 | done 14 | # Check if MariaDB is healthy 15 | if mariadb-admin status; then 16 | echo "MariaDB is up and running" 17 | if [ $# -eq 0 ]; then 18 | GREEN='\033[1;32m' 19 | NC='\033[0m' 20 | # No arguments provided, prompt for input 21 | printf "''${GREEN}Enter the site name: ''${NC}"; read -r site_name 22 | printf "''${GREEN}Set as new default? (y/N): ''${NC}"; read -r set_default 23 | 24 | (bench new-site --admin-password admin --db-root-password root "$site_name") 25 | if [ "$set_default" = "y" ]; then 26 | (bench use "$site_name") 27 | fi 28 | printf "User: ''${GREEN}%s''${NC} Password: ''${GREEN}%s''${NC}" "Administrator" "admin" 29 | echo 30 | else 31 | (bench new-site "$@") 32 | fi 33 | else 34 | echo "MariaDB failed to start properly" 35 | exit 1 36 | fi 37 | '') 38 | // { 39 | meta = { 40 | description = "Launch database and set up new site"; 41 | requiresArgs = ["run"]; 42 | }; 43 | }; 44 | drop-site = 45 | (writeBashBin "drop-site.sh" '' 46 | start-mariadb-for-frappe & 47 | MARIA_PID=$! 48 | trap "kill -SIGTERM $MARIA_PID && wait $MARIA_PID" EXIT 49 | (bench drop-site "$@") 50 | '') 51 | // { 52 | meta = { 53 | description = "Launch database and drop site"; 54 | requiresArgs = ["run"]; 55 | }; 56 | }; 57 | run-env = 58 | (writeBashBin "run-env.sh" '' 59 | exec process-compose up "$@" 60 | '') 61 | // {meta.description = "Launch the entire environment or a particular sub-service";}; 62 | } 63 | -------------------------------------------------------------------------------- /SCOPE.md: -------------------------------------------------------------------------------- 1 | # Frappix Scope 2 | 3 | ## Introduction 4 | 5 | Frappix bridges the gap between system dependencies and such that are already available in Python. 6 | 7 | It brings the power of the _entire_ software ecosystem to Frappé, not only the Python ecosystem. 8 | 9 | It achieves this by plugging into the [one of the biggest](https://repology.org/) software repositories to date. 10 | 11 | System dependencies are declared by their identifier in `pyproject.toml` and are then mapped to their available implementation from the backing software repository. 12 | 13 | When a user wants to start working on a project wired with Frappix, it is _guaranteed_ for him to be productive at exactly _on command_ away. Furthermore, the exact same environment used for development is recycled to produce a variety of production grade runtime artifacts, such as: 14 | 15 | - MicroVMs 16 | - VMs 17 | - Entire Host Operating System (fully configured) 18 | - OCI Containers 19 | 20 | Whatever deployment scenario can be supported by this infrastructure. 21 | 22 | The purpose, hence, of this work is to expand the _unified experience_ of the Frappé ecosystem beyond its current boundary which it inherits from its language ecosystems. 23 | 24 | ## Project Objectives 25 | 26 | - Quality assured and continually maintained onboarding story into the Frappé framework 27 | - A comprehensive development environment for Linux & macOS (Windows on WSL2, only) 28 | - Fully supported deployment targets: VM, MicroVM, Host OS, OCI Container 29 | - Appropriate documentation at its layer of the stack with clear interlinking to upstream documentation 30 | 31 | ## Scope 32 | 33 | - QA further the onboarding experience of the status quo 34 | - Ensure cross-platform support of the development environment 35 | - Implement OCI, MicroVM in addition to the status quo 36 | - Evaluate performance improvements of the associated tooling 37 | - Elaborate user and technical documentation 38 | 39 | ## Resources 40 | 41 | - Lead developer 42 | - Community contributions welcome! 43 | - Close collaboration with Frappé staff for up streaming necessary changes 44 | 45 | ## Risk 46 | 47 | - Sometimes a slow turnover of upstream PRs 48 | -------------------------------------------------------------------------------- /src/overlays/python/traceback-with-variables/01-fix-test-ouput.patch: -------------------------------------------------------------------------------- 1 | diff --git a/tests/dumps/test_main.argparse_code_script_help.txt b/tests/dumps/test_main.argparse_code_script_help.txt 2 | index 83622e1..c0239c3 100644 3 | --- a/tests/dumps/test_main.argparse_code_script_help.txt 4 | +++ b/tests/dumps/test_main.argparse_code_script_help.txt 5 | @@ -1,6 +1,6 @@ 6 | usage: code.py [-h] 7 | --a A 8 | 9 | -optional arguments: 10 | +options: 11 | -h, --help show this help message and exit 12 | --a A 13 | diff --git a/tests/dumps/test_main.module.txt b/tests/dumps/test_main.module.txt 14 | index 59737d1..659b0ba 100644 15 | --- a/tests/dumps/test_main.module.txt 16 | +++ b/tests/dumps/test_main.module.txt 17 | @@ -4,13 +4,14 @@ usage: server.py [-h] 18 | [--directory DIRECTORY] 19 | [port] 20 | positional arguments: 21 | - port Specify alternate port [default: 8000] 22 | -optional arguments: 23 | + port specify alternate port (default: 8000) 24 | + 25 | +options: 26 | -h, --help show this help message and exit 27 | - --cgi Run as CGI Server 28 | + --cgi run as CGI server 29 | --bind ADDRESS, -b ADDRESS 30 | - Specify alternate bind address [default: all 31 | - interfaces] 32 | ---directory DIRECTORY, -d DIRECTORY 33 | - Specify alternative directory [default:current 34 | - directory] 35 | + specify alternate bind address (default: all 36 | + interfaces) 37 | + --directory DIRECTORY, -d DIRECTORY 38 | + specify alternate directory (default: current 39 | + directory) 40 | diff --git a/tests/dumps/test_main.simple_code_tool_help.txt b/tests/dumps/test_main.simple_code_tool_help.txt 41 | index 33a15dc..daecd9c 100644 42 | --- a/tests/dumps/test_main.simple_code_tool_help.txt 43 | +++ b/tests/dumps/test_main.simple_code_tool_help.txt 44 | @@ -13,7 +13,7 @@ positional arguments: 45 | script 46 | script-arg 47 | 48 | -optional arguments: 49 | +options: 50 | -h, --help show this help message and exit 51 | --max-value-str-len MAX_VALUE_STR_LEN 52 | --max-exc-str-len MAX_EXC_STR_LEN 53 | -------------------------------------------------------------------------------- /src/overlays/python/rembg.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | buildPythonPackage, 4 | fetchPypi, 5 | setuptools, 6 | wheel, 7 | numpy, 8 | onnxruntime, 9 | opencv4, # opencv-python-headless, 10 | pillow, 11 | pooch, 12 | pymatting, 13 | scikit-image, 14 | scipy, 15 | tqdm, 16 | # - cli deps 17 | # aiohttp, 18 | # asyncer, 19 | # click, 20 | # fastapi, 21 | # filetype, 22 | # gradio, 23 | # python-multipart, 24 | # uvicorn, 25 | # watchdog, 26 | # - dev deps 27 | # bandit, 28 | # black, 29 | # flake8, 30 | # imagehash, 31 | # isort, 32 | # mypy, 33 | # pytest, 34 | # twine, 35 | # - gpu deps 36 | # onnxruntime-gpu, 37 | }: 38 | buildPythonPackage rec { 39 | pname = "rembg"; 40 | version = "2.0.49"; 41 | format = "pyproject"; 42 | 43 | src = fetchPypi { 44 | inherit pname version; 45 | hash = "sha256-LXfIfZu1pQMjp4OJ12ClyyA20RaQaqpPLHQZ3MeAkjo="; 46 | }; 47 | 48 | postPatch = '' 49 | substituteInPlace setup.py \ 50 | --replace "opencv-python-headless" "" 51 | ''; 52 | 53 | nativeBuildInputs = [ 54 | setuptools 55 | wheel 56 | ]; 57 | 58 | propagatedBuildInputs = [ 59 | numpy 60 | onnxruntime 61 | opencv4 # opencv-python-headless 62 | pillow 63 | pooch 64 | pymatting 65 | scikit-image 66 | scipy 67 | tqdm 68 | ]; 69 | 70 | # passthru.optional-dependencies = { 71 | # cli = [ 72 | # aiohttp 73 | # asyncer 74 | # click 75 | # fastapi 76 | # filetype 77 | # gradio 78 | # python-multipart 79 | # uvicorn 80 | # watchdog 81 | # ]; 82 | # dev = [ 83 | # bandit 84 | # black 85 | # flake8 86 | # imagehash 87 | # isort 88 | # mypy 89 | # pytest 90 | # setuptools 91 | # twine 92 | # wheel 93 | # ]; 94 | # gpu = [ 95 | # onnxruntime-gpu 96 | # ]; 97 | # }; 98 | 99 | pythonImportsCheck = ["rembg"]; 100 | 101 | meta = with lib; { 102 | description = "Remove image background"; 103 | homepage = "https://pypi.org/project/rembg/"; 104 | license = licenses.mit; 105 | maintainers = with maintainers; [blaggacao]; 106 | }; 107 | } 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Frappix

4 |

A Frappe Development & Deployment Environment 5 |

6 | 7 | --- 8 | 9 | > [!NOTE] 10 | > 11 | > **Guided install** 12 | > 13 | > ```shell 14 | > bash <(curl https://blaggacao.github.io/frappix/install) frappe myproject 15 | > ``` 16 | 17 | [![Chat on Matrix](https://img.shields.io/matrix/frappix:matrix.org?server_fqdn=matrix.org&style=for-the-badge)](https://matrix.to/#/#frappix:matrix.org) 18 | 19 | It is best for now, to join the community in the chat until the docs are more elaborate! 20 | 21 | Frappix is a development and deployment environment designed to cover the full software delivery lifecycle from development to deployment and operation for Frappe-based projects. 22 | 23 | It is intended for developers and operator alike in their respective role in customer-facing or educational projects. 24 | 25 | It can be used in simple scenarios to prototype apps that could later be run on Frappé Cloud but also for very complex production deployments which required extensive customization and fork-like patching of the upstream framework. 26 | 27 | ### Motivation 28 | 29 | Frappix bridges the gap between system dependencies and such that are already available in Python. 30 | 31 | It brings the power of the _entire_ software ecosystem to Frappé, not only the Python ecosystem. 32 | 33 | It leverages Nix to achieve (close to) reproducible builds of your deployment artifacts, while Nixpkgs is leveraged for its vast amount of up to date and readily available packages across various language ecosystems. 34 | 35 | For example, it is near trivial to set up and run a LLM efficiently via llama.cpp alongside your production setup, while it _is_ trivial to provide a swalwart email service in-scope on the same project, set up a nightly backup with StorJ, tweak your database performance with hugepages, host you plausible analytics instance alongside, or even spin up an entire private chat solution based on the Matrix protocol, etc. 36 | 37 | ### Battle tested 38 | 39 | Frappix, and it's predecessor, has served the author very well during the last year in a complex and highly sofisticated production environment. 40 | 41 | Please contact me via the above Matrix Chat or the [Frappé Forum](https://discuss.frappe.io/) if you have any further inquiry. 42 | -------------------------------------------------------------------------------- /docs/custom-upstream.md: -------------------------------------------------------------------------------- 1 | # Custom Upstream (Frappé / ERP Next) 2 | 3 | There may be many situations where you need to patch upstream Frappé / ERP Next, either temporary or permanently. 4 | 5 | For example, it may take time to upstream a patch, and you need to carry your fixes in the meantime. 6 | 7 | You can easily pin your version of sources with the shipped source pinning mechanism. 8 | 9 | The sources (`_pins`) will be injected via `apps/pkgs.nix` on this line into the build and deployment pipeline: 10 | 11 | ```nix 12 | { 13 | appSources = prevFrappix.appSources.overrideScope (_: _: _pins); 14 | } 15 | ``` 16 | 17 | ## Add custom dependencies 18 | 19 | If you also need to add custom dependencies, it will be only slightly more difficult. 20 | 21 | 1. You need to ensure that the dependencies are packaged in your package set. 22 | 23 | - You can check if they are contained upstream in your current Nixpkgs pin 24 | - Or you can package them yourself in an overlay; for this you'd add something like the following snippet to the `inject` function in `apps/pkgs.nix`: 25 | 26 | ```nix 27 | { 28 | inject = final: prev { 29 | pythonPackagesExtensions = 30 | prev.pythonPackagesExtensions 31 | ++ [ 32 | (pyFinal: pyPrev: { 33 | python-qrcode = pyFinal.callPackage ./python-qrcode.nix {}; 34 | whatsfly = pyFinal.callPackage ./whatsfly.nix {}; 35 | matrix-nio = pyFinal.callPackage ./matrix-nio.nix {}; 36 | vrp-cli = pyFinal.callPackage ./vrp-cli {}; 37 | }) 38 | ]; 39 | # [...] 40 | }; 41 | } 42 | ``` 43 | 44 | 2. You can add them into the upstream build instructions like so, within the `inject` function: 45 | 46 | ```nix 47 | { 48 | frappix = prev.frappix.overrideScope (finalFrappix: prevFrappix: { 49 | frappe = prevFrappix.frappe.overridePythonAttrs (o: { 50 | propagatedBuildInputs = with prevFrappix.frappe.pythonModule.pkgs; 51 | o.propagatedBuildInputs 52 | ++ [ 53 | matrix-nio 54 | authlib 55 | whatsfly 56 | ]; 57 | }); 58 | erpnext = prevFrappix.erpnext.overridePythonAttrs (o: { 59 | propagatedBuildInputs = with prevFrappix.erpnext.pythonModule.pkgs; 60 | o.propagatedBuildInputs 61 | ++ [ 62 | vrp-cli 63 | shapely 64 | pyproj 65 | numpy 66 | scipy 67 | geojson 68 | ]; 69 | }); 70 | 71 | }; 72 | } 73 | 74 | ``` 75 | -------------------------------------------------------------------------------- /.github/workflows/weekly.yml: -------------------------------------------------------------------------------- 1 | name: Weekly Command Check 2 | 3 | on: 4 | schedule: 5 | - cron: '0 9 * * 1' # Runs at 10:00 MEZ (9:00 UTC) every Monday 6 | workflow_dispatch: # Allows manual triggering 7 | 8 | jobs: 9 | update-apps: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: write # 'write' access to repository contents 13 | pull-requests: write # 'write' access to pull requests 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: nixbuild/nix-quick-install-action@v29 17 | 18 | - name: Update Apps and Check OCI build 19 | id: run_commands 20 | run: | 21 | # Your commands here 22 | nix run .#x86_64-linux.src.pkgs.nvchecker-nix -- -c ./apps/sources/config.toml 23 | nix build '.#__std.actions.x86_64-linux."src"."oci-images"."frappix-base"."build"' 24 | 25 | - name: Commit changes 26 | run: | 27 | git config user.name "${{ github.actor }}" 28 | git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com" 29 | git add . 30 | git commit -m "Weekly update from automated check" || echo "No changes to commit" 31 | 32 | - name: Push changes 33 | uses: ad-m/github-push-action@master 34 | with: 35 | github_token: ${{ secrets.GITHUB_TOKEN }} 36 | branch: main 37 | 38 | - name: Create Pull Request 39 | uses: peter-evans/create-pull-request@v7 40 | with: 41 | commit-message: "build: automatic weekly apps update" 42 | title: Weekly Apps Update 43 | body: | 44 | This is an automated pull request created after successful execution of the weekly update and command check. 45 | 46 | Changes made: 47 | 48 | - `nix run .#x86_64-linux.src.pkgs.nvchecker-nix -- -c ./apps/sources/config.toml` 49 | - `nix build '.#__std.actions.x86_64-linux."src"."oci-images"."frappix-base"."build"'` 50 | 51 | branch: weekly-update 52 | base: main 53 | 54 | - name: Send Telegram notification on failure 55 | if: failure() || steps.run_commands.outcome == 'failure' 56 | uses: appleboy/telegram-action@master 57 | with: 58 | to: ${{ secrets.TELEGRAM_CHAT_ID }} 59 | token: ${{ secrets.TELEGRAM_BOT_TOKEN }} 60 | message: | 61 | Weekly command check failed! 62 | Repository: ${{ github.repository }} 63 | See workflow run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/overlays/tools/mkSiteAssets.nix: -------------------------------------------------------------------------------- 1 | { 2 | runCommand, 3 | symlinkJoin, 4 | yarn, 5 | rsync, 6 | lib, 7 | }: apps: let 8 | assets = runCommand "frappe-apps-assets" {buildInputs = [yarn rsync];} '' 9 | mkdir -p $out/share/sites/assets $out/share/apps sites/assets apps 10 | 11 | umask u=rwx,go=rx 12 | 13 | cat ${appsList} 14 | 15 | # Cannot symlink because the build needs a writable source tree 16 | while read app; do 17 | name=''${app%%:*} 18 | path=''${app##*:} 19 | rsync -a --prune-empty-dirs \ 20 | --include '*/public/*' \ 21 | --exclude '/cypress/*' \ 22 | --exclude '/.github/*' \ 23 | --exclude '*/*.py' \ 24 | $path/ $out/share/apps/$name 25 | # cp -r $path $out/share/apps/$name 26 | echo "$name" >> $out/share/sites/apps.txt # used by esbuild to discover apps 27 | ls $out/share/apps/$name 28 | done < ${appsList} 29 | 30 | echo "... of which have node dependencies ..." 31 | find $out/share/apps -name 'node_modules' -type d -prune 32 | echo 33 | 34 | pushd $out/share/apps/frappe 35 | 36 | # Redis connection should fail and 'assets_json' chache key will not be deleted 37 | # This chache key should be deleted on service startup so that frappe recreates 38 | # the cache key on the very first access 39 | 40 | FRAPPE_REDIS_CACHE=unix:///dev/null 41 | export FRAPPE_REDIS_CACHE 42 | 43 | yarn --offline production 44 | 45 | unset FRAPPE_REDIS_CACHE 46 | 47 | popd 48 | 49 | pushd $out/share/sites/assets # already holds some build artifacts from above 50 | 51 | emplacePublicAndNodeModules() { 52 | echo 53 | echo "Emplace assets for: $2" 54 | [[ ! -d $2 ]] && mkdir $2 55 | if [[ -e "$out/share/apps/$2/$2/public" ]]; then 56 | find "$out/share/apps/$2/$2/public" -mindepth 1 -maxdepth 1 | \ 57 | xargs -I '{}' bash -c "echo linking {}; ln -s {} $2/"'$(basename {})' 58 | fi 59 | if [[ -e "$out/share/apps/$2/node_modules" ]]; then 60 | echo "linking $out/share/apps/$2/node_modules" 61 | ln -s "$out/share/apps/$2/node_modules" "$2/node_modules" 62 | fi 63 | } 64 | 65 | while read app; do 66 | name=''${app%%:*} 67 | path=''${app##*:} 68 | emplacePublicAndNodeModules "$path" "$name" 69 | done < ${appsList} 70 | 71 | popd 72 | ''; 73 | 74 | appsList = runCommand "apps.list" {} '' 75 | touch $out 76 | cat << LIST > $out 77 | ${ 78 | lib.concatMapStringsSep "\n" 79 | (f: "${f.pname}:${f.src.outPath}") 80 | apps 81 | } 82 | LIST 83 | ''; 84 | in 85 | assets 86 | -------------------------------------------------------------------------------- /src/overlays/libs/redi-search/cmake-fixes.patch: -------------------------------------------------------------------------------- 1 | diff --git a/cpu_features.cmake b/cpu_features.cmake1 2 | index 1760b47..720d118 100644 3 | --- a/deps/VectorSimilarity/cmake/cpu_features.cmake 4 | +++ b/deps/VectorSimilarity/cmake/cpu_features.cmake 5 | @@ -3,7 +3,6 @@ option(BUILD_TESTING "" OFF) 6 | option(CMAKE_POSITION_INDEPENDENT_CODE "" ON) 7 | FetchContent_Declare( 8 | cpu_features 9 | - GIT_REPOSITORY https://github.com/google/cpu_features.git 10 | - GIT_TAG 438a66e41807cd73e0c403966041b358f5eafc68 11 | + SOURCE_DIR @cpu_features@ 12 | ) 13 | FetchContent_MakeAvailable(cpu_features) 14 | 15 | diff --git a/deps/readies/cmake/cc b/deps/readies/cmake/cc 16 | index c931922..4301991 100644 17 | --- a/deps/readies/cmake/cc 18 | +++ b/deps/readies/cmake/cc 19 | @@ -26,10 +26,6 @@ endif() 20 | #---------------------------------------------------------------------------------------------- 21 | 22 | function(extract_debug_symbols TARGET) 23 | - if (NOT DEBUG AND NOT APPLE) 24 | - add_custom_command(TARGET ${TARGET} POST_BUILD 25 | - COMMAND "$ENV{MK}/extract-obj-symbols" "$") 26 | - endif() 27 | endfunction() 28 | 29 | #---------------------------------------------------------------------------------------------- 30 | 31 | diff --git a/deps/readies/shibumi/functions b/deps/readies/shibumi/functions 32 | index 683c526..5993158 100755 33 | --- a/deps/readies/shibumi/functions 34 | +++ b/deps/readies/shibumi/functions 35 | @@ -137,14 +137,7 @@ is_command() { 36 | 37 | get_profile_d() { 38 | local d 39 | - if [[ `uname -s` == Darwin ]]; then 40 | - d="$HOME/.profile.d" 41 | - else 42 | - d="/etc/profile.d" 43 | - fi 44 | - if [[ ! -d $d ]]; then 45 | - mkdir -p "$d" 46 | - fi 47 | + d="$NIX_BUILD_TOP/.profile.d" 48 | echo "$d" 49 | } 50 | 51 | @@ -152,16 +145,9 @@ setup_profile_d() { 52 | local d 53 | local profile 54 | local sudo 55 | - if [[ `uname -s` == Darwin ]]; then 56 | - d="$HOME/.profile.d" 57 | - profile="$HOME/.bash_profile" 58 | - [[ ! -f $profile ]] && touch $profile 59 | - sudo= 60 | - else 61 | - d="/etc/profile.d" 62 | - profile="/etc/profile" 63 | - sudo="$SUDO" 64 | - fi 65 | + d="$NIX_BUILD_TOP/.profile.d" 66 | + profile="$NIX_BUILD_TOP/.bash_profile" 67 | + sudo= 68 | if [[ ! -d $d ]]; then 69 | $sudo mkdir -p "$d" 70 | fi 71 | @@ -189,16 +175,8 @@ add_to_profile_d() { 72 | local files="$@" 73 | local d 74 | local sudo 75 | - if [[ `uname -s` == Darwin ]]; then 76 | - d="$HOME/.profile.d" 77 | - sudo= 78 | - else 79 | - d="/etc/profile.d" 80 | - sudo="$SUDO" 81 | - fi 82 | - if [[ ! -d $d ]]; then 83 | - $sudo mkdir -p $d 84 | - fi 85 | + d="$NIX_BUILD_TOP/.profile.d" 86 | + sudo= 87 | local f 88 | for f in $files; do 89 | $sudo cp $f $d/ 90 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Frappe Development & Deployment Environment"; 3 | 4 | outputs = { 5 | std, 6 | self, 7 | ... 8 | } @ inputs: 9 | std.growOn { 10 | inherit inputs; 11 | cellsFrom = std.incl ./. ["src" "local" "apps" "examples" "tests"]; 12 | cellBlocks = with std.blockTypes; [ 13 | (data "templates") 14 | 15 | # Pkgs Functions for Frappe Framework Components 16 | (functions "overlays") 17 | (pkgs "pkgs") 18 | 19 | # App Sources 20 | (self.nvchecker "sources") 21 | 22 | # Modules 23 | (anything "nixos") 24 | (anything "shell") 25 | (nixostests "nixos-tests") 26 | (microvms "vms") 27 | (runnables "jobs" // {cli = false;}) # for downstream use 28 | 29 | # containers 30 | (anything "oci") # really: oci modules 31 | (containers "oci-images" {ci.publish = true;}) 32 | (arion "arion-compose") 33 | 34 | # local 35 | (anything "config" // {cli = false;}) 36 | (devshells "shells") 37 | ]; 38 | } 39 | { 40 | packages = std.winnow (n: _: n == "frx") self ["src" "pkgs"]; 41 | shellModule = std.harvest self ["src" "shell" "bench"]; 42 | toolsOverlay = std.harvest self ["src" "overlays" "tools"]; 43 | pythonOverlay = std.harvest self ["src" "overlays" "python"]; 44 | frappeOverlay = std.harvest self ["src" "overlays" "frappe"]; 45 | libsOverlay = std.harvest self ["src" "overlays" "libs"]; 46 | nixosModules = std.harvest self ["src" "nixos"]; 47 | frapper = import ./std/frapper.nix {inherit inputs;}; 48 | nvchecker = import ./std/nvchecker.nix {inherit inputs;}; 49 | templates = std.pick self ["examples" "templates"]; 50 | }; 51 | 52 | inputs.nixpkgs.url = "github:nixos/nixpkgs/release-24.11"; 53 | 54 | inputs = { 55 | std.url = "github:divnix/std/v0.33.4"; 56 | devshell.url = "github:numtide/devshell"; 57 | devshell.inputs.nixpkgs.follows = "nixpkgs"; 58 | nixago.url = "github:nix-community/nixago"; 59 | nixago.inputs.nixpkgs.follows = "nixpkgs"; 60 | nixago.inputs.nixago-exts.follows = ""; 61 | microvm.url = "github:astro/microvm.nix"; 62 | microvm.inputs.nixpkgs.follows = "nixpkgs"; 63 | arion.url = "github:hercules-ci/arion"; 64 | arion.inputs.nixpkgs.follows = "nixpkgs"; 65 | # arion.inputs.hercules-ci-effects.follows = ""; 66 | n2c.url = "github:nlewo/nix2container"; 67 | # n2c.inputs.nixpkgs.follows = "nixpkgs"; 68 | std.inputs = { 69 | n2c.follows = "n2c"; 70 | nixpkgs.follows = "nixpkgs"; 71 | devshell.follows = "devshell"; 72 | nixago.follows = "nixago"; 73 | microvm.follows = "microvm"; 74 | arion.follows = "arion"; 75 | }; 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /src/overlays/tools/apps.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | writers, 4 | }: 5 | lib.lazyDerivation { 6 | derivation = writers.writeBashBin "apps" '' 7 | longest_appname="$(ls "$FRAPPE_APPS_PATH" | awk '{ print length }' | sort -nk1 | tail -n1)" 8 | bold=$(tput bold) 9 | blue=$(tput setaf 4) 10 | green=$(tput setaf 185) 11 | gray=$(tput setaf 245) 12 | normal=$(tput sgr0) 13 | indent="$(printf " %*s" $longest_appname)" 14 | 15 | while [[ $# -gt 0 ]]; do 16 | case $1 in 17 | -l|--list) 18 | LIST="$2" 19 | shift # past argument 20 | shift # past value 21 | ;; 22 | -r|--remotes) 23 | REMOTES=1 24 | shift # past argument 25 | ;; 26 | -*|--*) 27 | echo "Unknown option $1" 28 | exit 1 29 | ;; 30 | *) 31 | FRAGMENT=$1 32 | shift # past argument 33 | ;; 34 | esac 35 | done 36 | 37 | for app in $(ls "$FRAPPE_APPS_PATH"); do 38 | if [[ ! -e "$FRAPPE_APPS_PATH/$app/.git" ]]; then 39 | continue 40 | fi 41 | GIT_ARGS=( 42 | "--git-dir" "$FRAPPE_APPS_PATH/$app/.git" 43 | "--work-tree" "$FRAPPE_APPS_PATH/$app" 44 | ) 45 | 46 | current_branch="$(git ''${GIT_ARGS[@]} branch --show-current)" 47 | last_tag="$(git ''${GIT_ARGS[@]} describe --all)" 48 | app_fmt="$bold$blue%-''${longest_appname}s$normal $green%s$gray - %s$normal\n" 49 | printf "$app_fmt" "$app" "$current_branch" "$last_tag" 50 | 51 | fmt="$gray%s$normal\n" 52 | 53 | if ! [[ -z ''${LIST+x} ]]; then 54 | if ! [[ -z ''${REMOTES+x} ]]; then 55 | body="$(git ''${GIT_ARGS[@]} branch --remotes --list "$LIST/*" --verbose | sed "s/^/$indent/")" 56 | else 57 | body="$(git ''${GIT_ARGS[@]} branch --list "$LIST/*" --verbose --verbose | sed "s/^/$indent/")" 58 | fi 59 | elif ! [[ -z ''${REMOTES+x} ]]; then 60 | body="$(git ''${GIT_ARGS[@]} remote --verbose | sed "s/^/$indent/")" 61 | else 62 | body="$(git ''${GIT_ARGS[@]} status --short | sed "s/^/$indent/")" 63 | fi 64 | 65 | ! [[ -z ''${body// } ]] && printf "$fmt" "$body" 66 | 67 | done 68 | if ! [[ -z ''${FRAGMENT+x} ]]; then 69 | echo 70 | echo "Apps on $FRAGMENT:" 71 | while read LINE; do 72 | printf " %-''${longest_appname}s %s\n" "$(echo "$LINE" | cut -d' ' -f1)" "$(echo "$LINE" | cut -d' ' -f2)" 73 | done <<< "$( 74 | nix eval --raw --impure --no-warn-dirty --expr \ 75 | "with builtins.getFlake \"git+file:`pwd`\"; with nixpkgs.lib; concatStringsSep \"\n\" (map (a: a.pname + \" \" + a.version) nixosConfigurations.$FRAGMENT.config.services.frappe.apps)" 2>/dev/null 76 | )" 77 | fi 78 | ''; 79 | meta.description = "Interact with frappe apps"; 80 | } 81 | -------------------------------------------------------------------------------- /tests/nixos-tests.nix: -------------------------------------------------------------------------------- 1 | let 2 | inherit (inputs) nixpkgs; 3 | inherit (inputs.cells.src) pkgs nixos; 4 | inherit (inputs.nixpkgs) lib; 5 | 6 | site = "testproject.local"; 7 | project = "TestProject"; 8 | nixos-lib = import (nixpkgs + /nixos/lib) {inherit (nixpkgs) system;}; 9 | 10 | defaults = { 11 | nixpkgs = {inherit pkgs;}; 12 | virtualisation = { 13 | # we don't do any nix build inside the test vm 14 | writableStore = false; 15 | cores = 2; 16 | # diskSize = 8000; # MB 17 | memorySize = 4096; # MB 18 | forwardPorts = [ 19 | { 20 | guest.port = 80; 21 | host.port = 8080; 22 | } 23 | { 24 | guest.port = 443; 25 | host.port = 4433; 26 | } 27 | ]; 28 | }; 29 | }; 30 | in { 31 | nixos-tests = 32 | (nixos-lib.runTest { 33 | name = "frappe-test-nixos"; 34 | _file = ./tests.nix; 35 | skipLint = true; 36 | defaults = 37 | defaults 38 | // { 39 | imports = [ 40 | nixos.testrig 41 | nixos.frappix 42 | ]; 43 | }; 44 | hostPkgs = nixpkgs; 45 | nodes = { 46 | runnerA = {}; 47 | # runnerB = {}; 48 | # runnerC = {}; 49 | # runnerD = {}; 50 | }; 51 | testScript = 52 | # python 53 | '' 54 | def parallel(*fns): 55 | from threading import Thread 56 | threads = [ Thread(target=fn) for fn in fns ] 57 | for t in threads: t.start() 58 | for t in threads: t.join() 59 | 60 | start_all() 61 | total_builds = len(machines) 62 | 63 | with subtest("Wait for machines to reach target"): 64 | for idx, m in enumerate(machines): 65 | print("Check ", m) 66 | m.wait_for_unit("${project}.target") 67 | 68 | with subtest("Wait for site to become reachable"): 69 | for idx, m in enumerate(machines): 70 | print("Check ", m) 71 | m.wait_until_succeeds('test $(curl -L -s -o /dev/null -w %{http_code} ${site}) = 200', timeout=10) 72 | 73 | with subtest("Run the unit test suite"): 74 | for idx, m in enumerate(machines): 75 | print("bench run-parallel-tests for ", m) 76 | stdout = m.succeed(f"bench run-parallel-tests --build-number {idx+1} --total-builds {total_builds}") 77 | print(stdout) 78 | # parallel([ 79 | # m.succeed(f"bench run-parallel-tests --build-number {idx+1} --total-builds {total_builds}") 80 | # for idx, m in enumerate(machines) 81 | # ]) 82 | ''; 83 | }) 84 | // { 85 | meta.description = "The frappix vm-based test suite using nixos modules"; 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /apps/sources/config.toml: -------------------------------------------------------------------------------- 1 | [__config__] 2 | oldver = "versions.json" 3 | newver = "versions.json" 4 | nix-expr-folder = "." 5 | 6 | [bench] # only used for some static outputs 7 | source = "github" 8 | github = "frappe/bench" 9 | 10 | [frappe] 11 | source = "github" 12 | use_max_tag = true 13 | github = "frappe/frappe" 14 | 15 | [frappe.passthru] 16 | [frappe.passthru.clone] 17 | since = "version-14" 18 | [frappe.passthru.clone.upstream] 19 | fetch = [ 20 | "+refs/heads/develop:refs/remotes/upstream/develop", 21 | "+refs/heads/version-15:refs/remotes/upstream/version-15", 22 | "+refs/heads/version-15-hotfix:refs/remotes/upstream/version-15-hotfix", 23 | "+refs/tags/v15.*:refs/remotes/upstream/tags/v15.*", 24 | ] 25 | 26 | url = "https://github.com/frappe/frappe" 27 | [erpnext] 28 | source = "github" 29 | use_max_tag = true 30 | github = "frappe/erpnext" 31 | 32 | [erpnext.passthru] 33 | since = "version-14" 34 | upstream = """ 35 | URL: https://github.com/frappe/erpnext 36 | Pull: +refs/heads/develop:refs/remotes/upstream/develop 37 | Pull: +refs/heads/version-15:refs/remotes/upstream/version-15 38 | Pull: +refs/heads/version-15-hotfix:refs/remotes/upstream/version-15-hotfix 39 | Pull: +refs/tags/v15.*:refs/remotes/upstream/tags/v15.* 40 | """ 41 | 42 | [insights] 43 | source = "github" 44 | github = "frappe/insights" 45 | use_max_tag = true 46 | submodules = true 47 | exclude_regex = '.*-beta$' 48 | 49 | [gameplan] 50 | source = "github" 51 | github = "frappe/gameplan" 52 | use_commit = true 53 | submodules = true 54 | 55 | [crm] 56 | source = "github" 57 | github = "frappe/crm" 58 | use_max_tag = true 59 | submodules = true 60 | 61 | [builder] 62 | source = "github" 63 | use_max_tag = true 64 | github = "frappe/builder" 65 | submodules = true 66 | 67 | [print-designer] 68 | source = "github" 69 | use_max_tag = true 70 | github = "frappe/print_designer" 71 | 72 | [ecommerce-integrations] 73 | source = "github" 74 | github = "frappe/ecommerce_integrations" 75 | 76 | [payments] 77 | source = "github" 78 | branch = "version-15" # no proper releases 79 | github = "frappe/payments" 80 | 81 | [webshop] 82 | source = "github" 83 | branch = "version-15" # no proper releases 84 | github = "frappe/webshop" 85 | 86 | [wiki] 87 | source = "github" 88 | branch = "master" # Latest release (Wiki v2.0.1) is for frappe 14 89 | github = "frappe/wiki" 90 | 91 | [hrms] 92 | source = "github" 93 | use_max_tag = true 94 | github = "frappe/hrms" 95 | submodules = true 96 | 97 | [raven] 98 | source = "github" 99 | use_max_tag = true 100 | github = "The-Commit-Company/Raven" 101 | 102 | [raven.passthru] 103 | since = "v1.0.0" 104 | upstream = """ 105 | URL: https://github.com/The-Commit-Company/Raven 106 | Pull: +refs/heads/develop:refs/remotes/upstream/develop 107 | Pull: +refs/heads/main:refs/remotes/upstream/main 108 | """ 109 | 110 | [drive] 111 | source = "github" 112 | use_max_tag = true 113 | github = "frappe/drive" 114 | -------------------------------------------------------------------------------- /tests/arion-compose.nix: -------------------------------------------------------------------------------- 1 | let 2 | inherit (inputs.std.lib) dev; 3 | inherit (inputs.cells.src) oci-images; 4 | 5 | # // { 6 | # meta.description = "The frappix vm-based test suite using oci images"; 7 | # }; 8 | 9 | environment = { 10 | FRAPPE_REDIS_CACHE = "redis://redis-cache:6379"; 11 | FRAPPE_REDIS_QUEUE = "redis://redis-queue:6379"; 12 | FRAPPE_DB_HOST = "database"; 13 | FRAPPE_DB_PORT = 80; 14 | FRAPPE_SOCKETIO_PORT = 9000; 15 | }; 16 | image = oci-images.frappix-base.image.name; 17 | volumes = [ 18 | # "sysite:/var/lib/frappix/sites/mysite" 19 | ]; 20 | in { 21 | frappix = dev.mkArion { 22 | project.name = "frappix-oci-testbed"; 23 | docker-compose.volumes = { 24 | sites = {}; 25 | redis-cache-data = {}; 26 | redis-queue-data = {}; 27 | db-data = {}; 28 | }; 29 | services = { 30 | database.service = { 31 | image = "mariadb:10.6"; 32 | restart = "unless-stopped"; 33 | # healthcheck = { 34 | # test = [ 35 | # "mysqladmin" 36 | # "ping" 37 | # "-h" 38 | # "localhost" 39 | # "--password='changeit'" 40 | # ]; 41 | # interval = "1s"; 42 | # retries = 15; 43 | # }; 44 | command = [ 45 | "--character-set-server=utf8mb4" 46 | "--collation-server=utf8mb4_unicode_ci" 47 | "--skip-character-set-client-handshake" 48 | "--skip-innodb-read-only-compressed" 49 | ]; 50 | volumes = ["db-data:/var/lib/mysql"]; 51 | environment = { 52 | MYSQL_ROOT_PASSWORD = "changeit"; 53 | }; 54 | }; 55 | redis-cache.service = { 56 | image = "redis:6.2-alpine"; 57 | volumes = ["redis-cache-data:/data"]; 58 | }; 59 | redis-queue.service = { 60 | image = "redis:6.2-alpine"; 61 | volumes = ["redis-queue-data:/data"]; 62 | }; 63 | frontend.service = { 64 | inherit image environment volumes; 65 | depends_on = ["websocket" "backend"]; 66 | useHostStore = true; 67 | }; 68 | backend.service = { 69 | inherit image environment volumes; 70 | ports = ["8000:8000"]; 71 | useHostStore = true; 72 | }; 73 | websocket.service = { 74 | inherit image environment volumes; 75 | useHostStore = true; 76 | command = ["--websocket"]; 77 | ports = ["9000:9000"]; 78 | }; 79 | scheduler.service = { 80 | inherit image environment volumes; 81 | depends_on = ["database"]; 82 | command = ["--scheduler"]; 83 | useHostStore = true; 84 | }; 85 | worker-short.service = { 86 | inherit image environment volumes; 87 | depends_on = ["database"]; 88 | command = ["--worker=short"]; 89 | useHostStore = true; 90 | }; 91 | worker-long.service = { 92 | inherit image environment volumes; 93 | depends_on = ["database"]; 94 | command = ["--worker=long"]; 95 | useHostStore = true; 96 | }; 97 | }; 98 | }; 99 | } 100 | -------------------------------------------------------------------------------- /local/config.nix: -------------------------------------------------------------------------------- 1 | /* 2 | This file holds configuration data for repo dotfiles. 3 | 4 | Q: Why not just put the put the file there? 5 | 6 | A: (1) dotfile proliferation 7 | (2) have all the things in one place / fromat 8 | (3) potentially share / re-use configuration data - keeping it in sync 9 | */ 10 | { 11 | # Tool Homepage: https://editorconfig.org/ 12 | editorconfig = { 13 | data = { 14 | root = true; 15 | "*" = { 16 | end_of_line = "lf"; 17 | insert_final_newline = true; 18 | trim_trailing_whitespace = true; 19 | charset = "utf-8"; 20 | indent_style = "space"; 21 | indent_size = 2; 22 | }; 23 | "*.md" = { 24 | max_line_length = "off"; 25 | trim_trailing_whitespace = false; 26 | }; 27 | }; 28 | }; 29 | 30 | # Tool Homepage: https://numtide.github.io/treefmt/ 31 | treefmt = { 32 | packages = [ 33 | inputs.nixpkgs.alejandra 34 | inputs.nixpkgs.nodePackages.prettier 35 | inputs.nixpkgs.nodePackages.prettier-plugin-toml 36 | inputs.nixpkgs.shfmt 37 | ]; 38 | data = { 39 | formatter = { 40 | nix = { 41 | command = "alejandra"; 42 | includes = ["*.nix"]; 43 | excludes = ["apps/sources/generated.nix"]; 44 | }; 45 | prettier = { 46 | command = "prettier"; 47 | options = [ 48 | "--plugin" 49 | "${inputs.nixpkgs.nodePackages.prettier-plugin-toml}/lib/node_modules/prettier-plugin-toml/lib/index.js" 50 | "--write" 51 | ]; 52 | includes = [ 53 | "*.json" 54 | "*.md" 55 | "*.mdx" 56 | "*.yaml" 57 | "*.toml" 58 | ]; 59 | excludes = ["apps/sources/generated.json" "docs/README.md"]; 60 | }; 61 | shell = { 62 | command = "shfmt"; 63 | options = ["-i" "2" "-s" "-w"]; 64 | includes = ["*.sh"]; 65 | }; 66 | }; 67 | }; 68 | }; 69 | 70 | # Tool Homepage: https://github.com/evilmartians/lefthook 71 | lefthook = { 72 | data = { 73 | commit-msg = { 74 | commands = { 75 | conform = { 76 | # allow WIP, fixup!/squash! commits locally 77 | run = '' 78 | [[ "$(head -n 1 {1})" =~ ^WIP(:.*)?$|^wip(:.*)?$|fixup\!.*|squash\!.* ]] || 79 | conform enforce --commit-msg-file {1}''; 80 | skip = ["merge" "rebase"]; 81 | }; 82 | }; 83 | }; 84 | pre-commit = { 85 | commands = { 86 | treefmt = { 87 | run = "treefmt --fail-on-change {staged_files}"; 88 | skip = ["merge" "rebase"]; 89 | }; 90 | }; 91 | }; 92 | }; 93 | }; 94 | 95 | # Tool Homepage: https://rust-lang.github.io/mdBook/ 96 | mdbook = { 97 | # add preprocessor packages here 98 | packages = [ 99 | inputs.nixpkgs.mdbook-linkcheck 100 | ]; 101 | data = { 102 | # Configuration Reference: https://rust-lang.github.io/mdBook/format/configuration/index.html 103 | book = { 104 | language = "en"; 105 | multilingual = false; 106 | title = "Frappix Documentation"; 107 | src = "docs"; 108 | }; 109 | build.build-dir = "docs/build"; 110 | preprocessor = {}; 111 | output = { 112 | html = {}; 113 | # Tool Homepage: https://github.com/Michael-F-Bryan/mdbook-linkcheck 114 | linkcheck = {}; 115 | }; 116 | }; 117 | output = "book.toml"; 118 | hook.mode = "copy"; # let CI pick it up outside of devshell 119 | }; 120 | } 121 | -------------------------------------------------------------------------------- /docs/install: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | GREEN='\033[1;32m' 6 | NC='\033[0m' 7 | 8 | confirm() { 9 | if [ "$auto_yes" = "true" ]; then 10 | return 0 11 | fi 12 | echo 13 | printf "${GREEN}%s${NC} [Y/n] " "$1" 14 | read -r -n 1 response 15 | case "$response" in 16 | [nN][oO]|[nN]) return 1 ;; 17 | *) return 0 ;; 18 | esac 19 | } 20 | 21 | 22 | dependencies_ok() { 23 | if ! command -v nix >/dev/null 2>&1; then 24 | return 1 25 | fi 26 | if ! command -v direnv >/dev/null 2>&1; then 27 | return 1 28 | fi 29 | return 0 30 | } 31 | 32 | show_help() { 33 | echo "Usage: $0 [-y]