<commit_before>{ config, lib, pkgs, ... }:
with lib;
let
  inherit (pkgs) ipfs runCommand makeWrapper;

  cfg = config.services.ipfs;

  ipfsFlags = toString ([
    (optionalString  cfg.autoMount                   "--mount")
    (optionalString  cfg.autoMigrate                 "--migrate")
    (optionalString  cfg.enableGC                    "--enable-gc")
    (optionalString (cfg.serviceFdlimit != null)     "--manage-fdlimit=false")
    (optionalString (cfg.defaultMode == "offline")   "--offline")
    (optionalString (cfg.defaultMode == "norouting") "--routing=none")
  ] ++ cfg.extraFlags);

  defaultDataDir = if versionAtLeast config.system.stateVersion "17.09" then
    "/var/lib/ipfs" else
    "/var/lib/ipfs/.ipfs";

  # Wrapping the ipfs binary with the environment variable IPFS_PATH set to dataDir because we can't set it in the user environment
  wrapped = runCommand "ipfs" { buildInputs = [ makeWrapper ]; } ''
    mkdir -p "$out/bin"
    makeWrapper "${ipfs}/bin/ipfs" "$out/bin/ipfs" \
      --set IPFS_PATH ${cfg.dataDir} \
      --prefix PATH : /run/wrappers/bin
  '';


  commonEnv = {
    environment.IPFS_PATH = cfg.dataDir;
    path = [ wrapped ];
    serviceConfig.User = cfg.user;
    serviceConfig.Group = cfg.group;
  };

  baseService = recursiveUpdate commonEnv {
    wants = [ "ipfs-init.service" ];
    preStart = ''
      ipfs repo fsck # workaround for BUG #4212 (https://github.com/ipfs/go-ipfs/issues/4214)
      ipfs --local config Addresses.API ${cfg.apiAddress}
      ipfs --local config Addresses.Gateway ${cfg.gatewayAddress}
    '' + optionalString cfg.autoMount ''
      ipfs --local config Mounts.FuseAllowOther --json true
      ipfs --local config Mounts.IPFS ${cfg.ipfsMountDir}
      ipfs --local config Mounts.IPNS ${cfg.ipnsMountDir}
    '' + concatStringsSep "\n" (collect
          isString
          (mapAttrsRecursive
            (path: value:
            # Using heredoc below so that the value is never improperly quoted
            ''
              read value <<EOF
              ${builtins.toJSON value}
              EOF
              ipfs --local config --json "${concatStringsSep "." path}" "$value"
            '')
            cfg.extraConfig)
        );
    serviceConfig = {
      ExecStart = "${wrapped}/bin/ipfs daemon ${ipfsFlags}";
      Restart = "on-failure";
      RestartSec = 1;
    } // optionalAttrs (cfg.serviceFdlimit != null) { LimitNOFILE = cfg.serviceFdlimit; };
  };
in {

  ###### interface

  options = {

    services.ipfs = {

      enable = mkEnableOption "Interplanetary File System";

      user = mkOption {
        type = types.str;
        default = "ipfs";
        description = "User under which the IPFS daemon runs";
      };

      group = mkOption {
        type = types.str;
        default = "ipfs";
        description = "Group under which the IPFS daemon runs";
      };

      dataDir = mkOption {
        type = types.str;
        default = defaultDataDir;
        description = "The data dir for IPFS";
      };

      defaultMode = mkOption {
        type = types.enum [ "online" "offline" "norouting" ];
        default = "online";
        description = "systemd service that is enabled by default";
      };

      autoMigrate = mkOption {
        type = types.bool;
        default = false;
        description = "Whether IPFS should try to migrate the file system automatically";
      };

      autoMount = mkOption {
        type = types.bool;
        default = false;
        description = "Whether IPFS should try to mount /ipfs and /ipns at startup.";
      };

      ipfsMountDir = mkOption {
        type = types.str;
        default = "/ipfs";
        description = "Where to mount the IPFS namespace to";
      };

      ipnsMountDir = mkOption {
        type = types.str;
        default = "/ipns";
        description = "Where to mount the IPNS namespace to";
      };

      gatewayAddress = mkOption {
        type = types.str;
        default = "/ip4/127.0.0.1/tcp/8080";
        description = "Where the IPFS Gateway can be reached";<commit_msg>ipfs: disable autoMigrate option for now<commit_after>{ config, lib, pkgs, ... }:
with lib;
let
  inherit (pkgs) ipfs runCommand makeWrapper;

  cfg = config.services.ipfs;

  ipfsFlags = toString ([
    (optionalString  cfg.autoMount                   "--mount")
    #(optionalString  cfg.autoMigrate                 "--migrate")
    (optionalString  cfg.enableGC                    "--enable-gc")
    (optionalString (cfg.serviceFdlimit != null)     "--manage-fdlimit=false")
    (optionalString (cfg.defaultMode == "offline")   "--offline")
    (optionalString (cfg.defaultMode == "norouting") "--routing=none")
  ] ++ cfg.extraFlags);

  defaultDataDir = if versionAtLeast config.system.stateVersion "17.09" then
    "/var/lib/ipfs" else
    "/var/lib/ipfs/.ipfs";

  # Wrapping the ipfs binary with the environment variable IPFS_PATH set to dataDir because we can't set it in the user environment
  wrapped = runCommand "ipfs" { buildInputs = [ makeWrapper ]; } ''
    mkdir -p "$out/bin"
    makeWrapper "${ipfs}/bin/ipfs" "$out/bin/ipfs" \
      --set IPFS_PATH ${cfg.dataDir} \
      --prefix PATH : /run/wrappers/bin
  '';


  commonEnv = {
    environment.IPFS_PATH = cfg.dataDir;
    path = [ wrapped ];
    serviceConfig.User = cfg.user;
    serviceConfig.Group = cfg.group;
  };

  baseService = recursiveUpdate commonEnv {
    wants = [ "ipfs-init.service" ];
    # NB: migration must be performed prior to pre-start, else we get the failure message!
    preStart = ''
      ipfs repo fsck # workaround for BUG #4212 (https://github.com/ipfs/go-ipfs/issues/4214)
      ipfs --local config Addresses.API ${cfg.apiAddress}
      ipfs --local config Addresses.Gateway ${cfg.gatewayAddress}
    '' + optionalString cfg.autoMount ''
      ipfs --local config Mounts.FuseAllowOther --json true
      ipfs --local config Mounts.IPFS ${cfg.ipfsMountDir}
      ipfs --local config Mounts.IPNS ${cfg.ipnsMountDir}
    '' + concatStringsSep "\n" (collect
          isString
          (mapAttrsRecursive
            (path: value:
            # Using heredoc below so that the value is never improperly quoted
            ''
              read value <<EOF
              ${builtins.toJSON value}
              EOF
              ipfs --local config --json "${concatStringsSep "." path}" "$value"
            '')
            cfg.extraConfig)
        );
    serviceConfig = {
      ExecStart = "${wrapped}/bin/ipfs daemon ${ipfsFlags}";
      Restart = "on-failure";
      RestartSec = 1;
    } // optionalAttrs (cfg.serviceFdlimit != null) { LimitNOFILE = cfg.serviceFdlimit; };
  };
in {

  ###### interface

  options = {

    services.ipfs = {

      enable = mkEnableOption "Interplanetary File System";

      user = mkOption {
        type = types.str;
        default = "ipfs";
        description = "User under which the IPFS daemon runs";
      };

      group = mkOption {
        type = types.str;
        default = "ipfs";
        description = "Group under which the IPFS daemon runs";
      };

      dataDir = mkOption {
        type = types.str;
        default = defaultDataDir;
        description = "The data dir for IPFS";
      };

      defaultMode = mkOption {
        type = types.enum [ "online" "offline" "norouting" ];
        default = "online";
        description = "systemd service that is enabled by default";
      };

      /*
      autoMigrate = mkOption {
        type = types.bool;
        default = false;
        description = ''
          Whether IPFS should try to migrate the file system automatically.

          The daemon will need to be able to download a binary from https://ipfs.io to perform the migration.
        '';
      };
      */

      autoMount = mkOption {
        type = types.bool;
        default = false;
        description = "Whether IPFS should try to mount /ipfs and /ipns at startup.";
      };

      ipfsMountDir = mkOption {
        type = types.str;
        default = "/ipfs";
        description = "Where to mount the IPFS namespace to";
      };

      ipnsMountDir = mkOption {
        type = types.str;
        default = "/ipns";
        description = "Where to mount the IPNS namespace to";
      };

      gatewayAddress = mkOption {
        type = types.str;
        default = "/ip4/127.0.0.1/tcp/8080";
        description = "Where the IPFS Gateway can be reached";
{'fraction_non_alphanumeric': 0.11729055258467024, 'fraction_numerical': 0.00570409982174688, 'mean_word_length': 2.1135775064742877, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5101986', 'n_tokens_mistral': 2524, 'n_tokens_neox': 2439, 'n_words': 685}