Module for gitit

This commit is contained in:
Mats Rauhala 2021-12-31 13:35:22 +02:00
commit 78340b56f7
6 changed files with 399 additions and 0 deletions

27
flake.lock Normal file
View File

@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1640871638,
"narHash": "sha256-ty6sGnJUQEkCd43At5U3DRQZD7rPARz5VginSW6hZ3k=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5b091d4fbe3b7b7493c3b46fe0842e4b30ea24b3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

54
flake.nix Normal file
View File

@ -0,0 +1,54 @@
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { self, nixpkgs }: rec {
overlay = final: prev: {
gitit = prev.callPackage ./gitit.nix {};
};
# Provide module for gitit
nixosModules = builtins.listToAttrs (map (x: {
name = x;
value = import (./modules + "/${x}");
}) (builtins.attrNames (builtins.readDir ./modules)));
# Provide the gitit binary. nixpkgs does provide the binary as well, but
# it's built from a version that has a critical bug, login doesn't work
packages.x86_64-linux.gitit = with nixpkgs.legacyPackages.x86_64-linux;
callPackage ./gitit {};
defaultPackage.x86_64-linux = packages.x86_64-linux.gitit;
# Nixos integration tests for basic functionality
checks.x86_64-linux.gitit =
nixpkgs.legacyPackages.x86_64-linux.nixosTest (
import ./test.nix { modules = builtins.attrValues self.nixosModules; }
);
# For playing around in a container
# sudo nixos-container create gitit --flake .
nixosConfigurations.container = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules =
[ ({ pkgs, ... }: {
imports = builtins.attrValues self.nixosModules ++ [];
boot.isContainer = true;
environment.systemPackages = [
];
# Let 'nixos-version --json' know about the Git revision
# of this flake.
system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev;
# Network configuration.
networking.useDHCP = false;
networking.firewall.allowedTCPPorts = [ 5001 ];
services.gitit = {
enable = true;
};
})
];
};
};
}

40
gitit/cabal.nix Normal file
View File

@ -0,0 +1,40 @@
{ mkDerivation, aeson, base, base64-bytestring, blaze-html
, bytestring, ConfigFile, containers, directory, doctemplates, feed
, fetchgit, filepath, filestore, ghc, ghc-paths, happstack-server
, hoauth2, hslogger, HStringTemplate, HTTP, http-client-tls
, http-conduit, json, lib, mtl, network, network-bsd, network-uri
, old-locale, old-time, pandoc, pandoc-types, parsec, pretty
, process, random, recaptcha, safe, SHA, skylighting, split, syb
, tagsoup, temporary, text, time, uri-bytestring, url, utf8-string
, uuid, xhtml, xml, xml-conduit, xml-types, xss-sanitize, zlib
}:
mkDerivation {
pname = "gitit";
version = "0.15.1.0";
src = fetchgit {
url = "https://github.com/jgm/gitit";
sha256 = "0rzjgi6q338n6cv74438q81v322x2wjrpa7zdvp47z6hrilwpqaa";
rev = "11a18b034cc49ddaca652ac745fd308405a1fdad";
fetchSubmodules = true;
};
isLibrary = true;
isExecutable = true;
enableSeparateDataOutput = true;
libraryHaskellDepends = [
aeson base base64-bytestring blaze-html bytestring ConfigFile
containers directory doctemplates feed filepath filestore ghc
ghc-paths happstack-server hoauth2 hslogger HStringTemplate HTTP
http-client-tls http-conduit json mtl network network-bsd
network-uri old-locale old-time pandoc pandoc-types parsec pretty
process random recaptcha safe SHA skylighting split syb tagsoup
temporary text time uri-bytestring url utf8-string uuid xhtml xml
xml-conduit xml-types xss-sanitize zlib
];
executableHaskellDepends = [
base bytestring directory filepath hslogger HTTP mtl network
network-uri syb text url utf8-string
];
description = "Wiki using happstack, git or darcs, and pandoc";
license = "GPL";
}

62
gitit/default.nix Normal file
View File

@ -0,0 +1,62 @@
{ lib, haskellPackages, haskell, removeReferencesTo
# “Plugins” are a fancy way of saying gitit will invoke
# GHC at *runtime*, which in turn makes it pull GHC
# into its runtime closure. Only enable if you really need
# that feature. But if you do youll want to use gitit
# as a library anyway.
, pluginSupport ? false
}:
# this is similar to what we do with the pandoc executable
let
plain = haskellPackages.callPackage ./cabal.nix {};
plugins =
if pluginSupport
then plain
else haskell.lib.compose.disableCabalFlag "plugins" plain;
static = haskell.lib.compose.justStaticExecutables plugins;
in
(haskell.lib.compose.overrideCabal (drv: {
buildTools = (drv.buildTools or []) ++ [ removeReferencesTo ];
}) static).overrideAttrs (drv: {
# These libraries are still referenced, because they generate
# a `Paths_*` module for figuring out their version.
# The `Paths_*` module is generated by Cabal, and contains the
# version, but also paths to e.g. the data directories, which
# lead to a transitive runtime dependency on the whole GHC distribution.
# This should ideally be fixed in haskellPackages (or even Cabal),
# but a minimal gitit is important enough to patch it manually.
disallowedReferences = [
haskellPackages.pandoc-types
haskellPackages.HTTP
haskellPackages.pandoc
haskellPackages.happstack-server
haskellPackages.filestore
];
postInstall = ''
remove-references-to \
-t ${haskellPackages.pandoc-types} \
$out/bin/gitit
remove-references-to \
-t ${haskellPackages.HTTP} \
$out/bin/gitit
remove-references-to \
-t ${haskellPackages.pandoc} \
$out/bin/gitit
remove-references-to \
-t ${haskellPackages.happstack-server} \
$out/bin/gitit
remove-references-to \
-t ${haskellPackages.filestore} \
$out/bin/gitit
'';
meta = drv.meta // {
maintainers = drv.meta.maintainers or []
++ [ lib.maintainers.Profpatsch ];
};
})

159
modules/gitit/default.nix Normal file
View File

@ -0,0 +1,159 @@
{ config, lib, pkgs, ...}:
with lib;
let
cfg = config.services.gitit;
yesNo = b: if b then "yes" else "no";
gititConf = with cfg; pkgs.writeText "gitit.conf" ''
address: ${address}
port: ${toString port}
wiki-title: ${wiki-title}
repository-type: Git
repository-path: /var/lib/gitit/wikidata
require-authentication: ${require-authentication}
authentication-method: ${authentication-method}
static-dir: ${toString static-dir}
templates-dir: ${toString templates-dir}
cache-dir: /var/lib/gitit/cache
log-file: /var/lib/gitit/gitit.log
disable-registration: ${yesNo disable-registration}
access-question: ${access-question}
access-question-answers: ${access-question-answers}
'';
in
{
options.services.gitit = {
enable = mkEnableOption "gitit";
address = mkOption {
type = lib.types.str;
default = "0.0.0.0";
description = "Sets the IP address on which the web server will listen.";
};
port = mkOption {
type = lib.types.int;
default = 5001;
description = "Sets the port on which the web server will run.";
};
disable-registration = mkOption {
type = lib.types.bool;
default = false;
description = "If true, disables registering new users on the wiki";
};
wiki-title = mkOption {
type = lib.types.str;
default = "Wiki";
description = "The title of the wiki.";
};
access-question = mkOption {
type = lib.types.str;
default = "";
description = ''
specifies a question that users must answer when they attempt to create
an account, along with a comma-separated list of acceptable answers.
This can be used to institute a rudimentary password for signing up as
a user on the wiki, or as an alternative to reCAPTCHA.
Example:
access-question: What is the code given to you by Ms. X?
access-question-answers: RED DOG, red dog
'';
};
access-question-answers = mkOption {
type = lib.types.str;
default = "";
description = ''
specifies the answer that users must answer when they attempt to create
an account, along with a comma-separated list of acceptable answers.
This can be used to institute a rudimentary password for signing up as
a user on the wiki, or as an alternative to reCAPTCHA.
Example:
access-question: What is the code given to you by Ms. X?
access-question-answers: RED DOG, red dog
'';
};
require-authentication = mkOption {
type = lib.types.enum ["none" "read" "modify"];
default = "modify";
description = ''
if 'none' login is never required, and pages can be edited anonymously.
if 'modify', login is required to modify the wiki (edit, add, delete pages, upload files)
if 'read', login is required to see any wiki pages
'';
};
static-dir = mkOption {
type = lib.types.path;
default = "/var/lib/gitit/data/static";
description = ''
specifies the path of the static directory (containing javascript, css,
and images). If it does not exist, gitit will create it and populate it
with required scripts, stylesheets and images.
'';
};
templates-dir = mkOption {
type = lib.types.path;
default = "/var/lib/gitit/data/templates";
description = ''
specifies the path of the directory containing page templates. If it
does not exist, gitit will create it with default templates. Users may
with to edit the templates to customize the appearance of their wiki.
The template files are HStringTemplate templates. Variables to be
interpolated appear between $'s. Literal $'s must be backslash-escaped.
'';
};
authentication-method = mkOption {
type = lib.types.enum ["form" "http" "generic"];
default = "form";
description = ''
'form' means that users will be logged in and registered using forms in
the gitit web interface.
'http' means that gitit will assume that HTTP authentication is in
place and take the logged in username from the "Authorization" field of
the HTTP request header (in addition, the login/logout and registration
links will be suppressed).
'generic' means that gitit will assume that some form of authentication
is in place that directly sets REMOTE_USER to the name of the
authenticated user (e.g. mod_auth_cas on apache).
'rpx' means that gitit will attempt to log in through
https://rpxnow.com. This requires that 'rpx-domain', 'rpx-key', and
'base-url' be set below, and that 'curl' be in the system path.
'github' means that you are redirected to github website and need to
avail gitit to use your credential from there (github name and email).
Your email is used to identify you when you push your wiki data to git
to identify you as the author
'';
};
};
config = lib.mkIf cfg.enable {
users.users.gitit = {
home = "/var/lib/gitit";
createHome = true;
isSystemUser = true;
group = "gitit";
};
users.groups.gitit = {};
systemd.services.gitit = {
description = "Git and Pandoc Powered Wiki";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = with pkgs; [ curl git ];
preStart = ''
chown gitit:gitit -R /var/lib/gitit
'';
serviceConfig = {
User = config.users.users.gitit.name;
Group = config.users.groups.gitit.name;
ExecStart = "${pkgs.gitit}/bin/gitit -f ${gititConf}";
};
};
};
}

57
test.nix Normal file
View File

@ -0,0 +1,57 @@
{ modules }:
{
machine = { config, pkgs, lib, ... }:
{
imports = modules;
environment.systemPackages = [
pkgs.curl
];
services.gitit = {
enable = true;
port = 4001;
wiki-title = "Test Wiki";
address = "127.0.0.1";
};
networking.extraHosts = ''
127.0.0.1 wiki.local
'';
services.nginx = {
enable = true;
virtualHosts."wiki.local" = {
locations."/" = {
proxyPass = "http://127.0.0.1:4001";
};
};
};
};
testScript =
let username = "foo";
password = "foobar123";
form = "'username=${username}&email=&full_name_1=&password=${password}&password2=${password}&destination=%2F_index&register=Register'";
in
''
start_all()
machine.wait_for_unit("gitit.service")
machine.wait_for_open_port(4001)
if "Test Wiki" not in machine.succeed("curl -sS http://localhost:4001"):
raise Exception("Title not set properly")
machine.succeed("curl --data-raw ${form} 'http://localhost:4001/_register?destination=%2F_index'")
machine.wait_for_unit("nginx.service")
machine.wait_for_open_port(80)
if "Test Wiki" not in machine.succeed("curl -sS http://wiki.local:80"):
raise Exception("Wiki not available through nginx")
'';
}