Write peertube flake
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Tue, 15 Dec 2020 01:05:19 +0000 (02:05 +0100)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Thu, 21 Jan 2021 23:58:03 +0000 (00:58 +0100)
flakes/peertube/client.nix [new file with mode: 0644]
flakes/peertube/fix_yarn_lock.patch [new file with mode: 0644]
flakes/peertube/flake.lock [new file with mode: 0644]
flakes/peertube/flake.nix [new file with mode: 0644]
flakes/peertube/server.nix [new file with mode: 0644]

diff --git a/flakes/peertube/client.nix b/flakes/peertube/client.nix
new file mode 100644 (file)
index 0000000..06383a7
--- /dev/null
@@ -0,0 +1,28 @@
+{ yarnModulesConfig, mkYarnModules', server, sources, version, nodejs, stdenv }:
+rec {
+  modules = mkYarnModules' rec {
+    pname = "peertube-client-yarn-modules";
+    inherit version;
+    name = "${pname}-${version}";
+    packageJSON = "${sources}/client/package.json";
+    yarnLock = "${sources}/client/yarn.lock";
+    pkgConfig = yarnModulesConfig;
+  };
+  dist = stdenv.mkDerivation {
+    pname = "peertube-client";
+    inherit version;
+    src = sources;
+    buildPhase = ''
+          ln -s ${server.modules}/node_modules .
+          cp -a ${modules}/node_modules client/
+          chmod -R +w client/node_modules
+          patchShebangs .
+          npm run build:client
+    '';
+    installPhase = ''
+          mkdir $out
+          cp -a client/dist $out
+    '';
+    buildInputs = [ nodejs ];
+  };
+}
diff --git a/flakes/peertube/fix_yarn_lock.patch b/flakes/peertube/fix_yarn_lock.patch
new file mode 100644 (file)
index 0000000..241e31a
--- /dev/null
@@ -0,0 +1,28 @@
+diff --git a/client/yarn.lock b/client/yarn.lock
+index d27cdaec8..26706a9fc 100644
+--- a/client/yarn.lock
++++ b/client/yarn.lock
+@@ -5703,7 +5703,8 @@ http-errors@~1.7.2:
+ "http-node@github:feross/http-node#webtorrent":
+   version "1.2.0"
+-  resolved "https://codeload.github.com/feross/http-node/tar.gz/342ef8624495343ffd050bd0808b3750cf0e3974"
++  resolved "https://codeload.github.com/feross/http-node/tar.gz/342ef8624495343ffd050bd0808b3750cf0e3974#33fa312d37f0000b17acdb1a5086565400419a13"
++  integrity sha1-M/oxLTfwAAsXrNsaUIZWVABBmhM=
+   dependencies:
+     chrome-net "^3.3.3"
+     freelist "^1.0.3"
+diff --git a/yarn.lock b/yarn.lock
+index 61a2ea05e..c742276c7 100644
+--- a/yarn.lock
++++ b/yarn.lock
+@@ -3873,7 +3873,8 @@ http-errors@~1.7.2:
+ "http-node@github:feross/http-node#webtorrent":
+   version "1.2.0"
+-  resolved "https://codeload.github.com/feross/http-node/tar.gz/342ef8624495343ffd050bd0808b3750cf0e3974"
++  resolved "https://codeload.github.com/feross/http-node/tar.gz/342ef8624495343ffd050bd0808b3750cf0e3974#33fa312d37f0000b17acdb1a5086565400419a13"
++  integrity sha1-M/oxLTfwAAsXrNsaUIZWVABBmhM=
+   dependencies:
+     chrome-net "^3.3.3"
+     freelist "^1.0.3"
diff --git a/flakes/peertube/flake.lock b/flakes/peertube/flake.lock
new file mode 100644 (file)
index 0000000..b6fc1d0
--- /dev/null
@@ -0,0 +1,78 @@
+{
+  "nodes": {
+    "flake-utils": {
+      "locked": {
+        "lastModified": 1610051610,
+        "narHash": "sha256-U9rPz/usA1/Aohhk7Cmc2gBrEEKRzcW4nwPWMPwja4Y=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "3982c9903e93927c2164caa727cd3f6a0e6d14cc",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "myuids": {
+      "locked": {
+        "dir": "flakes/myuids",
+        "lastModified": 1611091761,
+        "narHash": "sha256-fE3FBeUxVaMezKjEpepdQW9apOza+0AfBALFhaaD0VA=",
+        "ref": "master",
+        "rev": "23f9fdf03a6673dbe334ae33be4f498cc4753191",
+        "revCount": 802,
+        "type": "git",
+        "url": "https://git.immae.eu/perso/Immae/Config/Nix.git"
+      },
+      "original": {
+        "dir": "flakes/myuids",
+        "type": "git",
+        "url": "https://git.immae.eu/perso/Immae/Config/Nix.git"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1611097871,
+        "narHash": "sha256-Q6bUkno5JNt0OoyXThFDrKArFBp/GryvJhwEgVzGSuk=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "31f5dd3f3655fbedac19f64f77844aa5ed79501c",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "peertube": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1610436329,
+        "narHash": "sha256-bIXt5bQiBBlNDFXYzcdQA8qp4nse5epUx/XQOguDOX8=",
+        "owner": "Chocobozzz",
+        "repo": "PeerTube",
+        "rev": "69e0e678beb7f1a3b6753eeff585a14f9a61ea86",
+        "type": "github"
+      },
+      "original": {
+        "owner": "Chocobozzz",
+        "ref": "v3.0.1",
+        "repo": "PeerTube",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "flake-utils": "flake-utils",
+        "myuids": "myuids",
+        "nixpkgs": "nixpkgs",
+        "peertube": "peertube"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flakes/peertube/flake.nix b/flakes/peertube/flake.nix
new file mode 100644 (file)
index 0000000..df6ef4a
--- /dev/null
@@ -0,0 +1,306 @@
+{
+  description = "A free software to take back control of your videos";
+  inputs.myuids = {
+    url = "https://git.immae.eu/perso/Immae/Config/Nix.git";
+    type = "git";
+    dir = "flakes/myuids";
+  };
+  inputs.flake-utils.url = "github:numtide/flake-utils";
+  inputs.nixpkgs.url = "github:NixOS/nixpkgs";
+  inputs.peertube = {
+    url = "github:Chocobozzz/PeerTube/v3.0.1";
+    flake = false;
+  };
+
+  outputs = { self, myuids, nixpkgs, peertube, flake-utils }: flake-utils.lib.eachSystem ["x86_64-linux"] (system:
+    let
+      version = (builtins.fromJSON (builtins.readFile ./flake.lock)).nodes.peertube.locked.rev;
+      pkgs = import nixpkgs { inherit system; overlays = [
+        (self: super: { nodejs = self.nodejs-12_x; })
+      ]; };
+      inherit (pkgs) callPackage stdenv jq youtube-dl fetchurl nodePackages yarn2nix-moretea;
+
+      patchedSource = stdenv.mkDerivation {
+        pname = "peertube";
+        inherit version;
+        src = peertube;
+        phases = [ "unpackPhase" "patchPhase" "installPhase" ];
+        patches = [ ./fix_yarn_lock.patch ];
+        installPhase = ''
+          mkdir $out
+          cp -a . $out/
+          '';
+      };
+      yarnModulesConfig = {
+        bcrypt = {
+          buildInputs = [ nodePackages.node-pre-gyp ];
+          postInstall = let
+            bcrypt_version = "5.0.0";
+            bcrypt_lib = fetchurl {
+              url = "https://github.com/kelektiv/node.bcrypt.js/releases/download/v${bcrypt_version}/bcrypt_lib-v${bcrypt_version}-napi-v3-linux-x64-glibc.tar.gz";
+              sha256 = "0j3p2px1xb17sw3gpm8l4apljajxxfflal1yy552mhpzhi21wccn";
+            };
+          in
+            ''
+              if [ "${bcrypt_version}" != "$(cat package.json | ${jq}/bin/jq -r .version)" ]; then
+                echo "Mismatching version please update bcrypt in derivation"
+                false
+              fi
+              mkdir -p lib/binding && tar -C lib/binding -xf ${bcrypt_lib}
+              patchShebangs ../node-pre-gyp
+              npm run install
+            '';
+        };
+        utf-8-validate = {
+          buildInputs = [ nodePackages.node-gyp-build ];
+        };
+        youtube-dl = {
+          postInstall = ''
+            mkdir bin
+            ln -s ${youtube-dl}/bin/youtube-dl bin/youtube-dl
+            cat > bin/details <<EOF
+            {"version":"${youtube-dl.version}","path":null,"exec":"youtube-dl"}
+            EOF
+            '';
+        };
+      };
+      mkYarnModules' = args: (yarn2nix-moretea.mkYarnModules args).overrideAttrs(old: {
+        # This hack permits to workaround the fact that the yarn.lock
+        # file doesn't respect the semver requirements
+        buildPhase = builtins.replaceStrings [" ./package.json"] [" /dev/null; cp deps/*/package.json ."] old.buildPhase;
+      });
+
+      server = callPackage ./server.nix {
+        inherit version yarnModulesConfig mkYarnModules';
+        sources = patchedSource;
+      };
+      client = callPackage ./client.nix {
+        inherit server version yarnModulesConfig mkYarnModules';
+        sources = patchedSource;
+      };
+
+    in rec {
+      packages.peertube = stdenv.mkDerivation rec {
+        inherit version;
+        pname = "peertube";
+        src = patchedSource;
+        buildPhase = ''
+          ln -s ${server.modules}/node_modules .
+          rm -rf dist && cp -a ${server.dist}/dist dist
+          rm -rf client/dist && cp -a ${client.dist}/dist client/
+          '';
+        installPhase = ''
+          mkdir $out
+          cp -a * $out
+          ln -s /tmp $out/.cache
+          '';
+
+        meta = {
+          description = "A free software to take back control of your videos";
+
+          longDescription = ''
+            PeerTube aspires to be a decentralized and free/libre alternative to video
+            broadcasting services.
+            PeerTube is not meant to become a huge platform that would centralize
+            videos from all around the world. Rather, it is a network of
+            inter-connected small videos hosters.
+            Anyone with a modicum of technical skills can host a PeerTube server, aka
+            an instance. Each instance hosts its users and their videos. In this way,
+            every instance is created, moderated and maintained independently by
+            various administrators.
+            You can still watch from your account videos hosted by other instances
+            though if the administrator of your instance had previously connected it
+            with other instances.
+          '';
+
+          license = stdenv.lib.licenses.agpl3Plus;
+
+          homepage = "https://joinpeertube.org/";
+
+          platforms = stdenv.lib.platforms.unix;
+        };
+      };
+      defaultPackage = packages.peertube;
+      legacyPackages.peertube = packages.peertube;
+      checks = {
+        build = defaultPackage;
+      } // pkgs.lib.optionalAttrs (builtins.elem system pkgs.lib.systems.doubles.linux) {
+        test =
+          let testing = import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; };
+          in testing.makeTest {
+            nodes = {
+              client = { pkgs, ... }: {};
+
+              server = { pkgs, ... }: {
+                imports = [ self.nixosModule ];
+                config.networking.firewall.allowedTCPPorts = [ 8888 ];
+                config.services.redis.enable = true;
+                config.services.postgresql = {
+                  enable = true;
+                  initialScript = pkgs.writeText "peertube.sql" ''
+                    CREATE ROLE "peertube" WITH LOGIN PASSWORD 'peertube';
+                    CREATE DATABASE "peertube_prod" WITH OWNER "peertube"
+                      TEMPLATE template0
+                      LC_COLLATE = "C"
+                      LC_CTYPE = "C";
+                    \c peertube_prod
+                    CREATE EXTENSION unaccent;
+                    CREATE EXTENSION pg_trgm;
+                  '';
+                };
+                config.services.peertube.enable = true;
+                config.services.peertube.configFile = pkgs.writeText "peertube.conf" ''
+                  listen:
+                    hostname: '0.0.0.0'
+                    port: 8888
+                  webserver:
+                    https: false
+                    hostname: 'localhost.tld'
+                    port: 8888
+                  database:
+                    hostname: 'localhost'
+                    port: 5432
+                    suffix: '_prod'
+                    username: 'peertube'
+                    password: 'peertube'
+                    pool:
+                      max: 5
+                  redis:
+                    socket: 'localhost'
+                    auth: null
+                    db: 0
+                  storage:
+                    tmp: '/var/lib/peertube/storage/tmp/'
+                    avatars: '/var/lib/peertube/storage/avatars/'
+                    videos: '/var/lib/peertube/storage/videos/'
+                    streaming_playlists: '/var/lib/peertube/storage/streaming-playlists/'
+                    redundancy: '/var/lib/peertube/storage/videos/'
+                    logs: '/var/lib/peertube/storage/logs/'
+                    previews: '/var/lib/peertube/storage/previews/'
+                    thumbnails: '/var/lib/peertube/storage/thumbnails/'
+                    torrents: '/var/lib/peertube/storage/torrents/'
+                    captions: '/var/lib/peertube/storage/captions/'
+                    cache: '/var/lib/peertube/storage/cache/'
+                    plugins: '/var/lib/peertube/storage/plugins/'
+                    client_overrides: '/var/lib/peertube/storage/client-overrides/'
+                  '';
+              };
+            };
+            testScript = ''
+              start_all()
+              server.wait_for_unit("peertube.service")
+              server.wait_for_open_port(8888)
+              client.succeed("curl http://server:8888")
+              client.succeed("curl http://server:8888/client/fr-FR/index.html")
+            '';
+          };
+      };
+    }
+  ) // {
+    nixosModule = { lib, pkgs, config, ... }:
+      let
+        name = "peertube";
+        cfg = config.services.peertube;
+      in
+      {
+        options.services.peertube = {
+          enable = lib.mkEnableOption "Enable Peertube’s service";
+          user = lib.mkOption {
+            type = lib.types.str;
+            default = name;
+            description = "User account under which Peertube runs";
+          };
+          group = lib.mkOption {
+            type = lib.types.str;
+            default = name;
+            description = "Group under which Peertube runs";
+          };
+          dataDir = lib.mkOption {
+            type = lib.types.path;
+            default = "/var/lib/${name}";
+            description = ''
+              The directory where Peertube stores its data.
+            '';
+          };
+          configFile = lib.mkOption {
+            type = lib.types.path;
+            description = ''
+              The configuration file path for Peertube.
+            '';
+          };
+          package = lib.mkOption {
+            type = lib.types.package;
+            default = self.defaultPackage."${pkgs.system}";
+            description = ''
+              Peertube package to use.
+            '';
+          };
+          # Output variables
+          systemdStateDirectory = lib.mkOption {
+            type = lib.types.str;
+            # Use ReadWritePaths= instead if varDir is outside of /var/lib
+            default = assert lib.strings.hasPrefix "/var/lib/" cfg.dataDir;
+                          lib.strings.removePrefix "/var/lib/" cfg.dataDir;
+            description = ''
+              Adjusted Peertube data directory for systemd
+            '';
+            readOnly = true;
+          };
+        };
+
+        config = lib.mkIf cfg.enable {
+          users.users = lib.optionalAttrs (cfg.user == name) {
+            "${name}" = {
+              uid = myuids.lib.uids.peertube;
+              group = cfg.group;
+              description = "Peertube user";
+              home = cfg.dataDir;
+              useDefaultShell = true;
+            };
+          };
+          users.groups = lib.optionalAttrs (cfg.group == name) {
+            "${name}" = {
+              gid = myuids.lib.gids.peertube;
+            };
+          };
+
+          systemd.services.peertube = {
+            description = "Peertube";
+            wantedBy = [ "multi-user.target" ];
+            after = [ "network.target" "postgresql.service" ];
+            wants = [ "postgresql.service" ];
+
+            environment.NODE_CONFIG_DIR = "${cfg.dataDir}/config";
+            environment.NODE_ENV = "production";
+            environment.HOME = cfg.package;
+
+            path = [ pkgs.nodejs pkgs.bashInteractive pkgs.ffmpeg pkgs.openssl ];
+
+            script = ''
+              install -m 0750 -d ${cfg.dataDir}/config
+              ln -sf ${cfg.configFile} ${cfg.dataDir}/config/production.yaml
+              ln -sf ${cfg.package}/config/default.yaml ${cfg.dataDir}/config/default.yaml
+              exec npm run start
+            '';
+
+            serviceConfig = {
+              User = cfg.user;
+              Group = cfg.group;
+              WorkingDirectory = cfg.package;
+              StateDirectory = cfg.systemdStateDirectory;
+              StateDirectoryMode = 0750;
+              PrivateTmp = true;
+              ProtectHome = true;
+              ProtectControlGroups = true;
+              Restart = "always";
+              Type = "simple";
+              TimeoutSec = 60;
+            };
+
+            unitConfig.RequiresMountsFor = cfg.dataDir;
+          };
+        };
+      };
+
+  };
+}
diff --git a/flakes/peertube/server.nix b/flakes/peertube/server.nix
new file mode 100644 (file)
index 0000000..1bba06d
--- /dev/null
@@ -0,0 +1,26 @@
+{ yarnModulesConfig, mkYarnModules', sources, version, nodejs, stdenv }:
+rec {
+  modules = mkYarnModules' rec {
+    pname = "peertube-server-yarn-modules";
+    inherit version;
+    name = "${pname}-${version}";
+    packageJSON = "${sources}/package.json";
+    yarnLock = "${sources}/yarn.lock";
+    pkgConfig = yarnModulesConfig;
+  };
+  dist = stdenv.mkDerivation {
+    pname = "peertube-server";
+    inherit version;
+    src = sources;
+    buildPhase = ''
+      ln -s ${modules}/node_modules .
+      patchShebangs scripts/build/server.sh
+      npm run build:server
+    '';
+    installPhase = ''
+      mkdir $out
+      cp -a dist $out
+    '';
+    buildInputs = [ nodejs ];
+  };
+}