at 23.05-pre 26 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.gitit; 8 9 homeDir = "/var/lib/gitit"; 10 11 toYesNo = b: if b then "yes" else "no"; 12 13 gititShared = with cfg.haskellPackages; gitit + "/share/" + ghc.targetPrefix + ghc.haskellCompilerName + "/" + gitit.pname + "-" + gitit.version; 14 15 gititWithPkgs = hsPkgs: extras: hsPkgs.ghcWithPackages (self: with self; [ gitit ] ++ (extras self)); 16 17 gititSh = hsPkgs: extras: with pkgs; let 18 env = gititWithPkgs hsPkgs extras; 19 in writeScript "gitit" '' 20 #!${runtimeShell} 21 cd $HOME 22 export NIX_GHC="${env}/bin/ghc" 23 export NIX_GHCPKG="${env}/bin/ghc-pkg" 24 export NIX_GHC_DOCDIR="${env}/share/doc/ghc/html" 25 export NIX_GHC_LIBDIR=$( $NIX_GHC --print-libdir ) 26 ${env}/bin/gitit -f ${configFile} 27 ''; 28 29 gititOptions = { 30 31 enable = mkOption { 32 type = types.bool; 33 default = false; 34 description = lib.mdDoc "Enable the gitit service."; 35 }; 36 37 haskellPackages = mkOption { 38 default = pkgs.haskellPackages; 39 defaultText = literalExpression "pkgs.haskellPackages"; 40 example = literalExpression "pkgs.haskell.packages.ghc784"; 41 description = lib.mdDoc "haskellPackages used to build gitit and plugins."; 42 }; 43 44 extraPackages = mkOption { 45 type = types.functionTo (types.listOf types.package); 46 default = self: []; 47 example = literalExpression '' 48 haskellPackages: [ 49 haskellPackages.wreq 50 ] 51 ''; 52 description = lib.mdDoc '' 53 Extra packages available to ghc when running gitit. The 54 value must be a function which receives the attrset defined 55 in {var}`haskellPackages` as the sole argument. 56 ''; 57 }; 58 59 address = mkOption { 60 type = types.str; 61 default = "0.0.0.0"; 62 description = lib.mdDoc "IP address on which the web server will listen."; 63 }; 64 65 port = mkOption { 66 type = types.int; 67 default = 5001; 68 description = lib.mdDoc "Port on which the web server will run."; 69 }; 70 71 wikiTitle = mkOption { 72 type = types.str; 73 default = "Gitit!"; 74 description = lib.mdDoc "The wiki title."; 75 }; 76 77 repositoryType = mkOption { 78 type = types.enum ["git" "darcs" "mercurial"]; 79 default = "git"; 80 description = lib.mdDoc "Specifies the type of repository used for wiki content."; 81 }; 82 83 repositoryPath = mkOption { 84 type = types.path; 85 default = homeDir + "/wiki"; 86 description = lib.mdDoc '' 87 Specifies the path of the repository directory. If it does not 88 exist, gitit will create it on startup. 89 ''; 90 }; 91 92 requireAuthentication = mkOption { 93 type = types.enum [ "none" "modify" "read" ]; 94 default = "modify"; 95 description = lib.mdDoc '' 96 If 'none', login is never required, and pages can be edited 97 anonymously. If 'modify', login is required to modify the wiki 98 (edit, add, delete pages, upload files). If 'read', login is 99 required to see any wiki pages. 100 ''; 101 }; 102 103 authenticationMethod = mkOption { 104 type = types.enum [ "form" "http" "generic" "github" ]; 105 default = "form"; 106 description = lib.mdDoc '' 107 'form' means that users will be logged in and registered using forms 108 in the gitit web interface. 'http' means that gitit will assume that 109 HTTP authentication is in place and take the logged in username from 110 the "Authorization" field of the HTTP request header (in addition, 111 the login/logout and registration links will be suppressed). 112 'generic' means that gitit will assume that some form of 113 authentication is in place that directly sets REMOTE_USER to the name 114 of the authenticated user (e.g. mod_auth_cas on apache). 'rpx' means 115 that gitit will attempt to log in through https://rpxnow.com. This 116 requires that 'rpx-domain', 'rpx-key', and 'base-url' be set below, 117 and that 'curl' be in the system path. 118 ''; 119 }; 120 121 userFile = mkOption { 122 type = types.path; 123 default = homeDir + "/gitit-users"; 124 description = lib.mdDoc '' 125 Specifies the path of the file containing user login information. If 126 it does not exist, gitit will create it (with an empty user list). 127 This file is not used if 'http' is selected for 128 authentication-method. 129 ''; 130 }; 131 132 sessionTimeout = mkOption { 133 type = types.int; 134 default = 60; 135 description = lib.mdDoc '' 136 Number of minutes of inactivity before a session expires. 137 ''; 138 }; 139 140 staticDir = mkOption { 141 type = types.path; 142 default = gititShared + "/data/static"; 143 description = lib.mdDoc '' 144 Specifies the path of the static directory (containing javascript, 145 css, and images). If it does not exist, gitit will create it and 146 populate it with required scripts, stylesheets, and images. 147 ''; 148 }; 149 150 defaultPageType = mkOption { 151 type = types.enum [ "markdown" "rst" "latex" "html" "markdown+lhs" "rst+lhs" "latex+lhs" ]; 152 default = "markdown"; 153 description = lib.mdDoc '' 154 Specifies the type of markup used to interpret pages in the wiki. 155 Possible values are markdown, rst, latex, html, markdown+lhs, 156 rst+lhs, and latex+lhs. (the +lhs variants treat the input as 157 literate Haskell. See pandoc's documentation for more details.) If 158 Markdown is selected, pandoc's syntax extensions (for footnotes, 159 delimited code blocks, etc.) will be enabled. Note that pandoc's 160 restructuredtext parser is not complete, so some pages may not be 161 rendered correctly if rst is selected. The same goes for latex and 162 html. 163 ''; 164 }; 165 166 math = mkOption { 167 type = types.enum [ "mathml" "raw" "mathjax" "jsmath" "google" ]; 168 default = "mathml"; 169 description = lib.mdDoc '' 170 Specifies how LaTeX math is to be displayed. Possible values are 171 mathml, raw, mathjax, jsmath, and google. If mathml is selected, 172 gitit will convert LaTeX math to MathML and link in a script, 173 MathMLinHTML.js, that allows the MathML to be seen in Gecko browsers, 174 IE + mathplayer, and Opera. In other browsers you may get a jumble of 175 characters. If raw is selected, the LaTeX math will be displayed as 176 raw LaTeX math. If mathjax is selected, gitit will link to the 177 remote mathjax script. If jsMath is selected, gitit will link to the 178 script /js/jsMath/easy/load.js, and will assume that jsMath has been 179 installed into the js/jsMath directory. This is the most portable 180 solution. If google is selected, the google chart API is called to 181 render the formula as an image. This requires a connection to google, 182 and might raise a technical or a privacy problem. 183 ''; 184 }; 185 186 mathJaxScript = mkOption { 187 type = types.str; 188 default = "https://d3eoax9i5htok0.cloudfront.net/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"; 189 description = lib.mdDoc '' 190 Specifies the path to MathJax rendering script. You might want to 191 use your own MathJax script to render formulas without Internet 192 connection or if you want to use some special LaTeX packages. Note: 193 path specified there cannot be an absolute path to a script on your 194 hdd, instead you should run your (local if you wish) HTTP server 195 which will serve the MathJax.js script. You can easily (in four lines 196 of code) serve MathJax.js using 197 http://happstack.com/docs/crashcourse/FileServing.html Do not forget 198 the "http://" prefix (e.g. http://localhost:1234/MathJax.js). 199 ''; 200 }; 201 202 showLhsBirdTracks = mkOption { 203 type = types.bool; 204 default = false; 205 description = lib.mdDoc '' 206 Specifies whether to show Haskell code blocks in "bird style", with 207 "> " at the beginning of each line. 208 ''; 209 }; 210 211 templatesDir = mkOption { 212 type = types.path; 213 default = gititShared + "/data/templates"; 214 description = lib.mdDoc '' 215 Specifies the path of the directory containing page templates. If it 216 does not exist, gitit will create it with default templates. Users 217 may wish to edit the templates to customize the appearance of their 218 wiki. The template files are HStringTemplate templates. Variables to 219 be interpolated appear between $\'s. Literal $\'s must be 220 backslash-escaped. 221 ''; 222 }; 223 224 logFile = mkOption { 225 type = types.path; 226 default = homeDir + "/gitit.log"; 227 description = lib.mdDoc '' 228 Specifies the path of gitit's log file. If it does not exist, gitit 229 will create it. The log is in Apache combined log format. 230 ''; 231 }; 232 233 logLevel = mkOption { 234 type = types.enum [ "DEBUG" "INFO" "NOTICE" "WARNING" "ERROR" "CRITICAL" "ALERT" "EMERGENCY" ]; 235 default = "ERROR"; 236 description = lib.mdDoc '' 237 Determines how much information is logged. Possible values (from 238 most to least verbose) are DEBUG, INFO, NOTICE, WARNING, ERROR, 239 CRITICAL, ALERT, EMERGENCY. 240 ''; 241 }; 242 243 frontPage = mkOption { 244 type = types.str; 245 default = "Front Page"; 246 description = lib.mdDoc '' 247 Specifies which wiki page is to be used as the wiki's front page. 248 Gitit creates a default front page on startup, if one does not exist 249 already. 250 ''; 251 }; 252 253 noDelete = mkOption { 254 type = types.str; 255 default = "Front Page, Help"; 256 description = lib.mdDoc '' 257 Specifies pages that cannot be deleted through the web interface. 258 (They can still be deleted directly using git or darcs.) A 259 comma-separated list of page names. Leave blank to allow every page 260 to be deleted. 261 ''; 262 }; 263 264 noEdit = mkOption { 265 type = types.str; 266 default = "Help"; 267 description = lib.mdDoc '' 268 Specifies pages that cannot be edited through the web interface. 269 Leave blank to allow every page to be edited. 270 ''; 271 }; 272 273 defaultSummary = mkOption { 274 type = types.str; 275 default = ""; 276 description = lib.mdDoc '' 277 Specifies text to be used in the change description if the author 278 leaves the "description" field blank. If default-summary is blank 279 (the default), the author will be required to fill in the description 280 field. 281 ''; 282 }; 283 284 tableOfContents = mkOption { 285 type = types.bool; 286 default = true; 287 description = lib.mdDoc '' 288 Specifies whether to print a tables of contents (with links to 289 sections) on each wiki page. 290 ''; 291 }; 292 293 plugins = mkOption { 294 type = with types; listOf str; 295 default = [ (gititShared + "/plugins/Dot.hs") ]; 296 description = lib.mdDoc '' 297 Specifies a list of plugins to load. Plugins may be specified either 298 by their path or by their module name. If the plugin name starts 299 with Gitit.Plugin., gitit will assume that the plugin is an installed 300 module and will not try to find a source file. 301 ''; 302 }; 303 304 useCache = mkOption { 305 type = types.bool; 306 default = false; 307 description = lib.mdDoc '' 308 Specifies whether to cache rendered pages. Note that if use-feed is 309 selected, feeds will be cached regardless of the value of use-cache. 310 ''; 311 }; 312 313 cacheDir = mkOption { 314 type = types.path; 315 default = homeDir + "/cache"; 316 description = lib.mdDoc "Path where rendered pages will be cached."; 317 }; 318 319 maxUploadSize = mkOption { 320 type = types.str; 321 default = "1000K"; 322 description = lib.mdDoc '' 323 Specifies an upper limit on the size (in bytes) of files uploaded 324 through the wiki's web interface. To disable uploads, set this to 325 0K. This will result in the uploads link disappearing and the 326 _upload url becoming inactive. 327 ''; 328 }; 329 330 maxPageSize = mkOption { 331 type = types.str; 332 default = "1000K"; 333 description = lib.mdDoc "Specifies an upper limit on the size (in bytes) of pages."; 334 }; 335 336 debugMode = mkOption { 337 type = types.bool; 338 default = false; 339 description = lib.mdDoc "Causes debug information to be logged while gitit is running."; 340 }; 341 342 compressResponses = mkOption { 343 type = types.bool; 344 default = true; 345 description = lib.mdDoc "Specifies whether HTTP responses should be compressed."; 346 }; 347 348 mimeTypesFile = mkOption { 349 type = types.path; 350 default = "/etc/mime/types.info"; 351 description = lib.mdDoc '' 352 Specifies the path of a file containing mime type mappings. Each 353 line of the file should contain two fields, separated by whitespace. 354 The first field is the mime type, the second is a file extension. 355 For example: 356 ``` 357 video/x-ms-wmx wmx 358 ``` 359 If the file is not found, some simple defaults will be used. 360 ''; 361 }; 362 363 useReCaptcha = mkOption { 364 type = types.bool; 365 default = false; 366 description = lib.mdDoc '' 367 If true, causes gitit to use the reCAPTCHA service 368 (http://recaptcha.net) to prevent bots from creating accounts. 369 ''; 370 }; 371 372 reCaptchaPrivateKey = mkOption { 373 type = with types; nullOr str; 374 default = null; 375 description = lib.mdDoc '' 376 Specifies the private key for the reCAPTCHA service. To get 377 these, you need to create an account at http://recaptcha.net. 378 ''; 379 }; 380 381 reCaptchaPublicKey = mkOption { 382 type = with types; nullOr str; 383 default = null; 384 description = lib.mdDoc '' 385 Specifies the public key for the reCAPTCHA service. To get 386 these, you need to create an account at http://recaptcha.net. 387 ''; 388 }; 389 390 accessQuestion = mkOption { 391 type = types.str; 392 default = "What is the code given to you by Ms. X?"; 393 description = lib.mdDoc '' 394 Specifies a question that users must answer when they attempt to 395 create an account 396 ''; 397 }; 398 399 accessQuestionAnswers = mkOption { 400 type = types.str; 401 default = "RED DOG, red dog"; 402 description = lib.mdDoc '' 403 Specifies a question that users must answer when they attempt to 404 create an account, along with a comma-separated list of acceptable 405 answers. This can be used to institute a rudimentary password for 406 signing up as a user on the wiki, or as an alternative to reCAPTCHA. 407 Example: 408 access-question: What is the code given to you by Ms. X? 409 access-question-answers: RED DOG, red dog 410 ''; 411 }; 412 413 rpxDomain = mkOption { 414 type = with types; nullOr str; 415 default = null; 416 description = lib.mdDoc '' 417 Specifies the domain and key of your RPX account. The domain is just 418 the prefix of the complete RPX domain, so if your full domain is 419 'https://foo.rpxnow.com/', use 'foo' as the value of rpx-domain. 420 ''; 421 }; 422 423 rpxKey = mkOption { 424 type = with types; nullOr str; 425 default = null; 426 description = lib.mdDoc "RPX account access key."; 427 }; 428 429 mailCommand = mkOption { 430 type = types.str; 431 default = "sendmail %s"; 432 description = lib.mdDoc '' 433 Specifies the command to use to send notification emails. '%s' will 434 be replaced by the destination email address. The body of the 435 message will be read from stdin. If this field is left blank, 436 password reset will not be offered. 437 ''; 438 }; 439 440 resetPasswordMessage = mkOption { 441 type = types.lines; 442 default = '' 443 > From: gitit@$hostname$ 444 > To: $useremail$ 445 > Subject: Wiki password reset 446 > 447 > Hello $username$, 448 > 449 > To reset your password, please follow the link below: 450 > http://$hostname$:$port$$resetlink$ 451 > 452 > Regards 453 ''; 454 description = lib.mdDoc '' 455 Gives the text of the message that will be sent to the user should 456 she want to reset her password, or change other registration info. 457 The lines must be indented, and must begin with '>'. The initial 458 spaces and '> ' will be stripped off. $username$ will be replaced by 459 the user's username, $useremail$ by her email address, $hostname$ by 460 the hostname on which the wiki is running (as returned by the 461 hostname system call), $port$ by the port on which the wiki is 462 running, and $resetlink$ by the relative path of a reset link derived 463 from the user's existing hashed password. If your gitit wiki is being 464 proxied to a location other than the root path of $port$, you should 465 change the link to reflect this: for example, to 466 http://$hostname$/path/to/wiki$resetlink$ or 467 http://gitit.$hostname$$resetlink$ 468 ''; 469 }; 470 471 useFeed = mkOption { 472 type = types.bool; 473 default = false; 474 description = lib.mdDoc '' 475 Specifies whether an ATOM feed should be enabled (for the site and 476 for individual pages). 477 ''; 478 }; 479 480 baseUrl = mkOption { 481 type = with types; nullOr str; 482 default = null; 483 description = lib.mdDoc '' 484 The base URL of the wiki, to be used in constructing feed IDs and RPX 485 token_urls. Set this if useFeed is false or authentication-method 486 is 'rpx'. 487 ''; 488 }; 489 490 absoluteUrls = mkOption { 491 type = types.bool; 492 default = false; 493 description = lib.mdDoc '' 494 Make wikilinks absolute with respect to the base-url. So, for 495 example, in a wiki served at the base URL '/wiki', on a page 496 Sub/Page, the wikilink `[Cactus]()` will produce a link to 497 '/wiki/Cactus' if absoluteUrls is true, and a relative link to 498 'Cactus' (referring to '/wiki/Sub/Cactus') if absolute-urls is 'no'. 499 ''; 500 }; 501 502 feedDays = mkOption { 503 type = types.int; 504 default = 14; 505 description = lib.mdDoc "Number of days to be included in feeds."; 506 }; 507 508 feedRefreshTime = mkOption { 509 type = types.int; 510 default = 60; 511 description = lib.mdDoc "Number of minutes to cache feeds before refreshing."; 512 }; 513 514 pdfExport = mkOption { 515 type = types.bool; 516 default = false; 517 description = lib.mdDoc '' 518 If true, PDF will appear in export options. PDF will be created using 519 pdflatex, which must be installed and in the path. Note that PDF 520 exports create significant additional server load. 521 ''; 522 }; 523 524 pandocUserData = mkOption { 525 type = with types; nullOr path; 526 default = null; 527 description = lib.mdDoc '' 528 If a directory is specified, this will be searched for pandoc 529 customizations. These can include a templates/ directory for custom 530 templates for various export formats, an S5 directory for custom S5 531 styles, and a reference.odt for ODT exports. If no directory is 532 specified, $HOME/.pandoc will be searched. See pandoc's README for 533 more information. 534 ''; 535 }; 536 537 xssSanitize = mkOption { 538 type = types.bool; 539 default = true; 540 description = lib.mdDoc '' 541 If true, all HTML (including that produced by pandoc) is filtered 542 through xss-sanitize. Set to no only if you trust all of your users. 543 ''; 544 }; 545 546 oauthClientId = mkOption { 547 type = with types; nullOr str; 548 default = null; 549 description = lib.mdDoc "OAuth client ID"; 550 }; 551 552 oauthClientSecret = mkOption { 553 type = with types; nullOr str; 554 default = null; 555 description = lib.mdDoc "OAuth client secret"; 556 }; 557 558 oauthCallback = mkOption { 559 type = with types; nullOr str; 560 default = null; 561 description = lib.mdDoc "OAuth callback URL"; 562 }; 563 564 oauthAuthorizeEndpoint = mkOption { 565 type = with types; nullOr str; 566 default = null; 567 description = lib.mdDoc "OAuth authorize endpoint"; 568 }; 569 570 oauthAccessTokenEndpoint = mkOption { 571 type = with types; nullOr str; 572 default = null; 573 description = lib.mdDoc "OAuth access token endpoint"; 574 }; 575 576 githubOrg = mkOption { 577 type = with types; nullOr str; 578 default = null; 579 description = lib.mdDoc "Github organization"; 580 }; 581 }; 582 583 configFile = pkgs.writeText "gitit.conf" '' 584 address: ${cfg.address} 585 port: ${toString cfg.port} 586 wiki-title: ${cfg.wikiTitle} 587 repository-type: ${cfg.repositoryType} 588 repository-path: ${cfg.repositoryPath} 589 require-authentication: ${cfg.requireAuthentication} 590 authentication-method: ${cfg.authenticationMethod} 591 user-file: ${cfg.userFile} 592 session-timeout: ${toString cfg.sessionTimeout} 593 static-dir: ${cfg.staticDir} 594 default-page-type: ${cfg.defaultPageType} 595 math: ${cfg.math} 596 mathjax-script: ${cfg.mathJaxScript} 597 show-lhs-bird-tracks: ${toYesNo cfg.showLhsBirdTracks} 598 templates-dir: ${cfg.templatesDir} 599 log-file: ${cfg.logFile} 600 log-level: ${cfg.logLevel} 601 front-page: ${cfg.frontPage} 602 no-delete: ${cfg.noDelete} 603 no-edit: ${cfg.noEdit} 604 default-summary: ${cfg.defaultSummary} 605 table-of-contents: ${toYesNo cfg.tableOfContents} 606 plugins: ${concatStringsSep "," cfg.plugins} 607 use-cache: ${toYesNo cfg.useCache} 608 cache-dir: ${cfg.cacheDir} 609 max-upload-size: ${cfg.maxUploadSize} 610 max-page-size: ${cfg.maxPageSize} 611 debug-mode: ${toYesNo cfg.debugMode} 612 compress-responses: ${toYesNo cfg.compressResponses} 613 mime-types-file: ${cfg.mimeTypesFile} 614 use-recaptcha: ${toYesNo cfg.useReCaptcha} 615 recaptcha-private-key: ${toString cfg.reCaptchaPrivateKey} 616 recaptcha-public-key: ${toString cfg.reCaptchaPublicKey} 617 access-question: ${cfg.accessQuestion} 618 access-question-answers: ${cfg.accessQuestionAnswers} 619 rpx-domain: ${toString cfg.rpxDomain} 620 rpx-key: ${toString cfg.rpxKey} 621 mail-command: ${cfg.mailCommand} 622 reset-password-message: ${cfg.resetPasswordMessage} 623 use-feed: ${toYesNo cfg.useFeed} 624 base-url: ${toString cfg.baseUrl} 625 absolute-urls: ${toYesNo cfg.absoluteUrls} 626 feed-days: ${toString cfg.feedDays} 627 feed-refresh-time: ${toString cfg.feedRefreshTime} 628 pdf-export: ${toYesNo cfg.pdfExport} 629 pandoc-user-data: ${toString cfg.pandocUserData} 630 xss-sanitize: ${toYesNo cfg.xssSanitize} 631 632 [Github] 633 oauthclientid: ${toString cfg.oauthClientId} 634 oauthclientsecret: ${toString cfg.oauthClientSecret} 635 oauthcallback: ${toString cfg.oauthCallback} 636 oauthauthorizeendpoint: ${toString cfg.oauthAuthorizeEndpoint} 637 oauthaccesstokenendpoint: ${toString cfg.oauthAccessTokenEndpoint} 638 github-org: ${toString cfg.githubOrg} 639 ''; 640 641in 642 643{ 644 645 options.services.gitit = gititOptions; 646 647 config = mkIf cfg.enable { 648 649 users.users.gitit = { 650 group = config.users.groups.gitit.name; 651 description = "Gitit user"; 652 home = homeDir; 653 createHome = true; 654 uid = config.ids.uids.gitit; 655 }; 656 657 users.groups.gitit.gid = config.ids.gids.gitit; 658 659 systemd.services.gitit = let 660 uid = toString config.ids.uids.gitit; 661 gid = toString config.ids.gids.gitit; 662 in { 663 description = "Git and Pandoc Powered Wiki"; 664 after = [ "network.target" ]; 665 wantedBy = [ "multi-user.target" ]; 666 path = with pkgs; [ curl ] 667 ++ optional cfg.pdfExport texlive.combined.scheme-basic 668 ++ optional (cfg.repositoryType == "darcs") darcs 669 ++ optional (cfg.repositoryType == "mercurial") mercurial 670 ++ optional (cfg.repositoryType == "git") git; 671 672 preStart = let 673 gm = "gitit@${config.networking.hostName}"; 674 in 675 with cfg; '' 676 chown ${uid}:${gid} -R ${homeDir} 677 for dir in ${repositoryPath} ${staticDir} ${templatesDir} ${cacheDir} 678 do 679 if [ ! -d $dir ] 680 then 681 mkdir -p $dir 682 find $dir -type d -exec chmod 0750 {} + 683 find $dir -type f -exec chmod 0640 {} + 684 fi 685 done 686 cd ${repositoryPath} 687 ${ 688 if repositoryType == "darcs" then 689 '' 690 if [ ! -d _darcs ] 691 then 692 darcs initialize 693 echo "${gm}" > _darcs/prefs/email 694 '' 695 else if repositoryType == "mercurial" then 696 '' 697 if [ ! -d .hg ] 698 then 699 hg init 700 cat >> .hg/hgrc <<NAMED 701[ui] 702username = gitit ${gm} 703NAMED 704 '' 705 else 706 '' 707 if [ ! -d .git ] 708 then 709 git init 710 git config user.email "${gm}" 711 git config user.name "gitit" 712 ''} 713 chown ${uid}:${gid} -R ${repositoryPath} 714 fi 715 cd - 716 ''; 717 718 serviceConfig = { 719 User = config.users.users.gitit.name; 720 Group = config.users.groups.gitit.name; 721 ExecStart = with cfg; gititSh haskellPackages extraPackages; 722 }; 723 }; 724 }; 725}