commit 8a8fe8cfc6abaa041649246fc657fad99d282070 Author: Leyla Becker Date: Thu Mar 13 01:31:34 2025 -0500 created module diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..8392d15 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce2538f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +result +.direnv +.vscode/* +!.vscode/settings.json \ No newline at end of file diff --git a/base-module.nix b/base-module.nix new file mode 100644 index 0000000..1aacb3a --- /dev/null +++ b/base-module.nix @@ -0,0 +1,3 @@ +config: { + options = (import ./configuration-type.nix) config; +} diff --git a/configuration-type.nix b/configuration-type.nix new file mode 100644 index 0000000..2fa9667 --- /dev/null +++ b/configuration-type.nix @@ -0,0 +1,120 @@ +{lib, ...}: let + folderType = lib.types.submodule ({name, ...}: { + options = { + id = lib.mkOption { + type = lib.types.string; + }; + label = lib.mkOption { + type = lib.types.string; + default = name; + }; + }; + }); +in { + folders = lib.mkOption { + type = lib.types.attrsOf folderType; + default = {}; + }; + devices = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + name = lib.mkOption { + type = lib.types.string; + default = name; + }; + id = lib.mkOption { + type = lib.types.string; + }; + folders = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ( + {config, ...}: { + options = { + folder = lib.mkOption { + type = folderType; + }; + path = lib.mkOption { + type = lib.types.string; + }; + type = lib.mkOption { + type = lib.types.enum ["sendreceive" "sendonly" "receiveonly" "receiveencrypted"]; + default = "sendreceive"; + }; + versioning = { + simple = { + enable = lib.mkEnableOption "should this folder use simple versioning"; + keep = lib.mkOption { + type = lib.types.string; + default = "10"; + }; + }; + trashcan = { + enable = lib.mkEnableOption "should this folder use trashcan versioning"; + cleanoutDays = lib.mkOption { + type = lib.types.string; + default = "1000"; + }; + }; + staggered = { + enable = lib.mkEnableOption "should this folder use staggard versioning"; + cleanInterval = lib.mkOption { + type = lib.types.string; + default = "3600"; + }; + maxAge = lib.mkOption { + type = lib.types.string; + default = "31536000"; + }; + }; + external = { + enable = lib.mkEnableOption "should this folder use external versioning"; + }; + }; + }; + # TODO: figure out how to make assertions for submodules + # config = { + # assertions = + # (lib.lists.optionals config.versioning.simple.enable [ + # { + # assertion = !config.versioning.trashcan.enable; + # message = "Can not use both simple and trashcan versioning at the same time."; + # } + # { + # assertion = !config.versioning.staggered.enable; + # message = "Can not use both simple and staggered versioning at the same time."; + # } + # { + # assertion = !config.versioning.external.enable; + # message = "Can not use both simple and external versioning at the same time."; + # } + # ]) + # ++ (lib.lists.optionals config.versioning.trashcan.enable [ + # { + # assertion = !config.versioning.staggered.enable; + # message = "Can not use both trashcan and staggered versioning at the same time."; + # } + # { + # assertion = !config.versioning.external.enable; + # message = "Can not use both trashcan and external versioning at the same time."; + # } + # ]) + # ++ (lib.lists.optionals config.versioning.staggered.enable [ + # { + # assertion = !config.versioning.external.enable; + # message = "Can not use both staggered and external versioning at the same time."; + # } + # ]) + # ++ [ + # { + # assertion = !config.versioning.external.enable; + # message = "External versioning currently not implemented."; + # } + # ]; + # }; + } + )); + }; + }; + })); + default = {}; + }; +} diff --git a/eval-config.nix b/eval-config.nix new file mode 100644 index 0000000..af4d6f5 --- /dev/null +++ b/eval-config.nix @@ -0,0 +1,9 @@ +{ + lib, + modules, +}: let + result = lib.evalModules { + inherit modules; + }; +in + result.config diff --git a/example-module.nix b/example-module.nix new file mode 100644 index 0000000..b4e27fb --- /dev/null +++ b/example-module.nix @@ -0,0 +1,47 @@ +{config, ...}: { + folders = { + documents = { + id = "aaaaa-aaaaa"; + }; + photos = { + id = "bbbbb-bbbbb"; + }; + }; + devices = { + desktop = { + id = "AAAAAAA-AAAAAAA-AAAAAAA-AAAAAAA-AAAAAAA-AAAAAAA-AAAAAAA-AAAAAAA"; + folders = { + documents = { + folder = config.folders.documents; + path = "/sync/user/documents"; + }; + photos = { + folder = config.folders.photos; + path = "/sync/user/photos"; + }; + }; + }; + laptop = { + id = "BBBBBBB-BBBBBBB-BBBBBBB-BBBBBBB-BBBBBBB-BBBBBBB-BBBBBBB-BBBBBBB"; + folders = { + documents = { + folder = config.folders.documents; + path = "/sync/documents"; + }; + photos = { + folder = config.folders.photos; + path = "/sync/photos"; + }; + }; + }; + phone = { + id = "CCCCCCC-CCCCCCC-CCCCCCC-CCCCCCC-CCCCCCC-CCCCCCC-CCCCCCC-CCCCCCC"; + folders = { + photos = { + folder = config.folders.photos; + path = "/sync/photos"; + }; + }; + }; + }; +} diff --git a/example-nixos-module.nix b/example-nixos-module.nix new file mode 100644 index 0000000..ddba306 --- /dev/null +++ b/example-nixos-module.nix @@ -0,0 +1,11 @@ +{ + lib, + self, + ... +}: { + services.syncthing = { + configuration = self.outputs.syncthingConfiguration; + deviceName = "laptop"; + }; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..028a99b --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1741037377, + "narHash": "sha256-SvtvVKHaUX4Owb+PasySwZsoc5VUeTf1px34BByiOxw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "02032da4af073d0f6110540c8677f16d4be0117f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..29bc6cd --- /dev/null +++ b/flake.nix @@ -0,0 +1,72 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + }; + + outputs = { + self, + nixpkgs, + ... + }: let + systems = [ + "aarch64-darwin" + "aarch64-linux" + "x86_64-darwin" + "x86_64-linux" + ]; + pkgsFor = system: nixpkgs.legacyPackages.${system}; + forEachSystem = nixpkgs.lib.genAttrs systems; + forEachPkgs = lambda: forEachSystem (system: lambda (pkgsFor system)); + in { + devShells = forEachPkgs (pkgs: { + default = pkgs.mkShell { + packages = with pkgs; [ + # for version controlling this repo + git + # for formatting code in this repo + alejandra + # for viewing configuration options defined in this repo + nix-inspect + ]; + }; + }); + + nixosModules.default = self.nixosModules.syncthing; + nixosModules.syncthing = import ./nixos.nix; + + # TODO: figure out if I need modules for these projects + # homeManagerModules.syncthing = null; + # darwinModules.syncthing = null; + + lib = { + evalConfig = import ./eval-config.nix; + syncthingConfiguration = {modules, ...}: + self.lib.evalConfig ( + {inherit (nixpkgs) lib;} + // { + modules = + modules + ++ [ + (import ./base-module.nix) + ]; + } + ); + }; + + nixosConfigurations = { + default = nixpkgs.lib.nixosSystem { + specialArgs = {inherit self;}; + modules = [ + self.nixosModules.syncthing + ./example-nixos-module.nix + ]; + }; + }; + + syncthingConfiguration = self.lib.syncthingConfiguration { + modules = [ + (import ./example-module.nix) + ]; + }; + }; +} diff --git a/nixos.nix b/nixos.nix new file mode 100644 index 0000000..e31d28b --- /dev/null +++ b/nixos.nix @@ -0,0 +1,43 @@ +{ + lib, + config, + ... +} @ input: { + options = { + services.syncthing = { + configuration = (import ./configuration-type.nix) input; + deviceName = lib.mkOption { + type = lib.types.string; + }; + }; + }; + + config = { + services.syncthing.settings = { + devices = + lib.attrsets.mapAttrs (name: deviceConfig: { + id = deviceConfig.id; + }) + config.services.syncthing.configuration.devices; + folders = + lib.attrsets.mapAttrs (folderName: folder: { + id = folder.folder.id; + label = folder.folder.label; + path = folder.path; + devices = lib.attrsets.mapAttrsToList (_: device: device.name) ( + lib.attrsets.filterAttrs ( + deviceName: device: + lib.lists.any + ( + deviceFolder: deviceFolder.folder.id == folder.folder.id + ) ( + lib.attrsets.mapAttrsToList (_: deviceFolder: deviceFolder) device.folders + ) + ) + config.services.syncthing.configuration.devices + ); + }) + config.services.syncthing.configuration.devices.${config.services.syncthing.deviceName}.folders; + }; + }; +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..d7c46b9 --- /dev/null +++ b/shell.nix @@ -0,0 +1,14 @@ +( + import + ( + let + lock = builtins.fromJSON (builtins.readFile ./flake.lock); + in + fetchTarball { + url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flake-compat.locked.narHash; + } + ) + {src = ./.;} +) +.shellNix