module draft
This commit is contained in:
parent
e2e0f134da
commit
22c105586b
4 changed files with 339 additions and 54 deletions
105
flake.lock
generated
105
flake.lock
generated
|
@ -1,5 +1,21 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
|
@ -18,13 +34,56 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1747372754,
|
||||
"narHash": "sha256-2Y53NGIX2vxfie1rOW0Qb86vjRZ7ngizoo+bnXU9D9k=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "80479b6ec16fefd9c1db3ea13aeb038c60530f46",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1745526057,
|
||||
"narHash": "sha256-ITSpPDwvLBZBnPRS2bUcHY3gZSwis/uTe255QgMtTLA=",
|
||||
"lastModified": 1748460289,
|
||||
"narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "f771eb401a46846c1aebd20552521b233dd7e18b",
|
||||
"rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -62,11 +121,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1744599653,
|
||||
"narHash": "sha256-nysSwVVjG4hKoOjhjvE6U5lIKA8sEr1d1QzEfZsannU=",
|
||||
"lastModified": 1748562898,
|
||||
"narHash": "sha256-STk4QklrGpM3gliPKNJdBLSQvIrqRuwHI/rnYb/5rh8=",
|
||||
"owner": "pyproject-nix",
|
||||
"repo": "build-system-pkgs",
|
||||
"rev": "7dba6dbc73120e15b558754c26024f6c93015dd7",
|
||||
"rev": "33bd58351957bb52dd1700ea7eeefe34de06a892",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -82,11 +141,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743438845,
|
||||
"narHash": "sha256-1GSaoubGtvsLRwoYwHjeKYq40tLwvuFFVhGrG8J9Oek=",
|
||||
"lastModified": 1746540146,
|
||||
"narHash": "sha256-QxdHGNpbicIrw5t6U3x+ZxeY/7IEJ6lYbvsjXmcxFIM=",
|
||||
"owner": "pyproject-nix",
|
||||
"repo": "pyproject.nix",
|
||||
"rev": "8063ec98edc459571d042a640b1c5e334ecfca1e",
|
||||
"rev": "e09c10c24ebb955125fda449939bfba664c467fd",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -98,12 +157,34 @@
|
|||
"root": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts",
|
||||
"hooks": "hooks",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pyproject-build-systems": "pyproject-build-systems",
|
||||
"pyproject-nix": "pyproject-nix",
|
||||
"treefmt": "treefmt",
|
||||
"uv2nix": "uv2nix"
|
||||
}
|
||||
},
|
||||
"treefmt": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1748243702,
|
||||
"narHash": "sha256-9YzfeN8CB6SzNPyPm2XjRRqSixDopTapaRsnTpXUEY8=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "1f3f7b784643d488ba4bf315638b2b0a4c5fb007",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"uv2nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
|
@ -114,11 +195,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1745697651,
|
||||
"narHash": "sha256-r4A/fkiCenEapHkjJWPiNUZEfviuXMCr6mRozJ5dC4o=",
|
||||
"lastModified": 1748398512,
|
||||
"narHash": "sha256-99mf47Kjl/rj716cSjeA6ubZLlhNudmC4HRg/6UMfvs=",
|
||||
"owner": "pyproject-nix",
|
||||
"repo": "uv2nix",
|
||||
"rev": "cb6508484d534dafd097713b575f2aebc3417de0",
|
||||
"rev": "f006d191d4ff5894d2ead6299e2eaf3659bc46b0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
51
flake.nix
51
flake.nix
|
@ -4,6 +4,14 @@
|
|||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
hooks = {
|
||||
url = "github:cachix/git-hooks.nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
treefmt = {
|
||||
url = "github:numtide/treefmt-nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
pyproject-nix = {
|
||||
url = "github:pyproject-nix/pyproject.nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
@ -21,29 +29,41 @@
|
|||
};
|
||||
};
|
||||
|
||||
outputs = {
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-parts,
|
||||
hooks,
|
||||
treefmt,
|
||||
uv2nix,
|
||||
pyproject-nix,
|
||||
pyproject-build-systems,
|
||||
...
|
||||
} @ inputs: let
|
||||
}@inputs:
|
||||
let
|
||||
workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; };
|
||||
overlay = workspace.mkPyprojectOverlay {
|
||||
sourcePreference = "wheel";
|
||||
};
|
||||
in
|
||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
systems = ["x86_64-linux" "aarch64-linux"];
|
||||
imports = [
|
||||
hooks.flakeModule
|
||||
treefmt.flakeModule
|
||||
];
|
||||
|
||||
perSystem = {
|
||||
systems = nixpkgs.lib.systems.flakeExposed;
|
||||
|
||||
perSystem =
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
inputs',
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
}:
|
||||
let
|
||||
python = pkgs.python313;
|
||||
pythonSet =
|
||||
(pkgs.callPackage pyproject-nix.build.packages {
|
||||
|
@ -55,7 +75,23 @@
|
|||
overlay
|
||||
]
|
||||
);
|
||||
in {
|
||||
in
|
||||
{
|
||||
treefmt = {
|
||||
projectRootFile = "flake.nix";
|
||||
|
||||
programs.nixfmt = {
|
||||
enable = true;
|
||||
package = pkgs.nixfmt-rfc-style;
|
||||
};
|
||||
|
||||
programs.ruff.enable = true;
|
||||
};
|
||||
|
||||
pre-commit.settings.hooks = {
|
||||
treefmt.enable = true;
|
||||
};
|
||||
|
||||
devShells.default = pkgs.mkShell {
|
||||
packages = [
|
||||
python
|
||||
|
@ -71,11 +107,14 @@
|
|||
LD_LIBRARY_PATH = lib.makeLibraryPath pkgs.pythonManylinuxPackages.manylinux1;
|
||||
};
|
||||
shellHook = ''
|
||||
${config.pre-commit.installationScript}
|
||||
unset PYTHONPATH
|
||||
'';
|
||||
};
|
||||
|
||||
packages.default = pythonSet.mkVirtualEnv "forgesync" workspace.deps.default;
|
||||
};
|
||||
|
||||
flake.nixosModules.default = import ./module.nix self;
|
||||
};
|
||||
}
|
||||
|
|
167
module.nix
Normal file
167
module.nix
Normal file
|
@ -0,0 +1,167 @@
|
|||
self:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
utils,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.forgesync;
|
||||
inherit (lib) types;
|
||||
inherit (utils.systemdUtils.unitOptions) unitOption;
|
||||
in
|
||||
{
|
||||
options.services.forgesync = {
|
||||
enable = lib.mkEnableOption "Forgesync";
|
||||
|
||||
package = lib.mkPackageOption self.packages.${pkgs.system} "default" { };
|
||||
|
||||
jobs = lib.mkOption {
|
||||
description = ''
|
||||
Synchronization jobs to run.
|
||||
'';
|
||||
default = { };
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
settings = lib.mkOption {
|
||||
default = { };
|
||||
example = {
|
||||
from-instance = "https://codeberg.org/api/v1";
|
||||
to = "github";
|
||||
to-instance = "https://api.github.com";
|
||||
remirror = true;
|
||||
description-template = "{description} (Mirror of {url})";
|
||||
mirror-interval = "8h0m0s";
|
||||
immediate = true;
|
||||
log = "INFO";
|
||||
};
|
||||
description = ''
|
||||
Settings for this Forgesync job.
|
||||
'';
|
||||
type =
|
||||
let
|
||||
simples = [
|
||||
types.bool
|
||||
types.str
|
||||
types.int
|
||||
types.float
|
||||
];
|
||||
in
|
||||
types.attrsOf (
|
||||
types.oneOf (
|
||||
simples
|
||||
++ [
|
||||
(types.listOf (types.oneOf simples))
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
secretFile = lib.mkOption {
|
||||
type = types.path;
|
||||
description = ''
|
||||
The EnvironmentFile for secrets required for Forgesync: `FROM_TOKEN`, `TO_TOKEN` and `MIRROR_TOKEN`.
|
||||
'';
|
||||
};
|
||||
|
||||
timerConfig = lib.mkOption {
|
||||
type = types.nullOr (types.attrsOf unitOption);
|
||||
default = {
|
||||
OnCalendar = "daily";
|
||||
Persistent = true;
|
||||
};
|
||||
description = ''
|
||||
When to run the job.
|
||||
'';
|
||||
};
|
||||
|
||||
inhibit = lib.mkOption {
|
||||
default = [ ];
|
||||
type = types.listOf (types.strMatching "^[^:]+$");
|
||||
example = [
|
||||
"sleep"
|
||||
];
|
||||
description = ''
|
||||
Run the Forgesync process with an inhibition lock taken;
|
||||
see {manpage}`systemd-inhibit(1)` for a list of possible operations.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd = lib.mkMerge (
|
||||
lib.mapAttrsToList (
|
||||
jobName: job:
|
||||
let
|
||||
unitName = "forgesync-job-${jobName}";
|
||||
description = "Forgesync job ${jobName}";
|
||||
in
|
||||
{
|
||||
timers.${unitName} = {
|
||||
wantedBy = [ "timers.target" ];
|
||||
inherit description;
|
||||
inherit (job) timerConfig;
|
||||
};
|
||||
|
||||
services.${unitName} = {
|
||||
after = [ "network.target" ];
|
||||
inherit description;
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
|
||||
DynamicUser = true;
|
||||
|
||||
ExecStart =
|
||||
let
|
||||
inhibitArgs = [
|
||||
(lib.getExe' config.systemd.package "systemd-inhibit")
|
||||
"--mode"
|
||||
"block"
|
||||
"--who"
|
||||
description
|
||||
"--what"
|
||||
(lib.concatStringsSep ":" job.inhibit)
|
||||
"--why"
|
||||
"Scheduled Forgesync job ${jobName}"
|
||||
"--"
|
||||
];
|
||||
|
||||
args =
|
||||
(lib.optionals (job.inhibit != [ ]) inhibitArgs)
|
||||
++ [ (lib.getExe cfg.package) ]
|
||||
++ (lib.cli.toGNUCommandLine { mkOptionName = k: "--${k}"; } job.settings);
|
||||
in
|
||||
utils.escapeSystemdExecArgs args;
|
||||
|
||||
EnvironmentFile = job.secretFile;
|
||||
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectControlGroups = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
LockPersonality = true;
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
];
|
||||
DevicePolicy = "closed";
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
) cfg.jobs
|
||||
);
|
||||
};
|
||||
}
|
|
@ -20,11 +20,9 @@ class PushMirrorConfig:
|
|||
def overlay(self: Self, other: Self) -> Self:
|
||||
result = type(self)()
|
||||
for f in fields(self):
|
||||
value = ( # pyright: ignore[reportAny]
|
||||
getattr(other, f.name)
|
||||
if getattr(other, f.name) is not None
|
||||
else getattr(self, f.name)
|
||||
)
|
||||
other_attr = getattr(other, f.name) # pyright: ignore[reportAny]
|
||||
self_attr = getattr(self, f.name) # pyright: ignore[reportAny]
|
||||
value = other_attr if other_attr is not None else self_attr # pyright: ignore[reportAny]
|
||||
setattr(result, f.name, value)
|
||||
return result
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue