diff --git a/modules/overlayfile/default.nix b/modules/overlayfile/default.nix index cccea01..7859350 100644 --- a/modules/overlayfile/default.nix +++ b/modules/overlayfile/default.nix @@ -1,31 +1,28 @@ # https://github.com/nix-community/home-manager/blob/master/modules/files.nix { config, lib, pkgs, ... }: with lib; let - _cfg = config.environment.overlay; - cfg = _cfg.users; - storePath = _cfg.tempStorePath; + cfg_ = config.environment.overlay; + cfg = cfg_.users; - fileType = (import ./file-type.nix { inherit lib pkgs; }); - inherit (import ./lib.nix { inherit lib; }) storeFileName; - sourceStorePath = file: - let - sourcePath = toString file.source; - sourceName = storeFileName (baseNameOf sourcePath); - in - if builtins.hasContext sourcePath - then file.source - else builtins.path { path = file.source; name = sourceName; }; + storePath = cfg_.tempStorePath; + inherit (import ./lib.nix { inherit lib; }) sourceStorePath; + + fileType = types.submoduleWith { + modules = [ (import ./file-type.nix) ]; + shorthandOnlyDefinesConfig = true; + specialArgs = { inherit pkgs; }; + }; in { options.environment.overlay = { users = mkOption { - type = types.attrsOf fileType; + type = with types; attrsOf (attrsOf fileType); default = {}; description = "Attribute set of files to link into the user home."; }; tempStorePath = mkOption { - type = types.nullOr types.str; - default = null; + type = types.str; + default = ""; description = "A path to store overlay files which is out of Nix store"; }; @@ -42,9 +39,9 @@ in { in { assertions = [ { - assertion = _cfg != null; + assertion = cfg_ != ""; message = '' - tempStorePath should not be Null when overlay files is enabled. + environment.overlay.tempStorePath should be set when overlay files is enabled. ''; } (let @@ -92,9 +89,9 @@ in { systemd.services = (folder (sum: user: files: let - next = "overlayfile-${user}-pre-mount.service"; - overlayPkg = pkgs.runCommand "overlay-packfile-${user}" - { nativeBuildInputs = with pkgs; [ coreutils ]; } + group = config.users.users.${user}.group; + + overlayPkg = pkgs.runCommand "overlay-packfile-${user}" {} ( (builtins.readFile ./scripts/insert_file.sh) + (traceVal (concatStrings ( @@ -107,114 +104,112 @@ in { ))) ); in { + # 1. Remove old files and copy new files' symlinks "overlayfile-${user}-copy-check" = let _store = "${storePath}/${user}"; storeHash = baseNameOf overlayPkg; storeLock = "${_store}-lock-${storeHash}"; - copyScript = pkgs.writeShellScriptBin "overlay-${user}-copy" '' - out="${_store}" - sou="$(realpath -m "${overlayPkg}")" - owner="${toString user}" - group="${toString config.users.users.${user}.group}" - - mkdir -p "$out" - rm -vf "$out-lock-"* - rm -vrf "$out"/* - rm -vrf "$out"/.* + next = "overlayfile-${user}-pre-mount.service"; + in { + description = "Check availablity of overlay files for ${user} and copy them"; + before = [ next ]; + requiredBy = [ next ]; + wantedBy = [ "local-fs.target" ]; + # bindsTo = "overlayfile-${user}-pre-mount.service"; - cp -vrfHL "$sou"/. "$out" - echo "$sou" > "${storeLock}" - chown -cR $owner:$group "$out" - chmod -cR 1700 "$out" - ''; + environment = { + OUT = _store; + }; - rmFlagScript = pkgs.writeShellScriptBin "overlay-${user}-rm-flag" '' - rm -r "${storeLock}" - ''; - in { - path = with pkgs; [ coreutils ]; unitConfig = { - Description = "Check availablity of overlay files for ${user} and copy them"; DefaultDependencies = "no"; - Before = next; - # BindsTo = "overlayfile-${user}-pre-mount.service"; ConditionPathExists = "!${storeLock}"; }; serviceConfig = { Type = "oneshot"; RemainAfterExit = "yes"; - ExecStart = "${getExe copyScript}"; - ExecStop = "${getExe rmFlagScript}"; }; - wantedBy = [ next "local-fs.target" ]; + script = '' + sou="$(realpath -m "${overlayPkg}")" + + mkdir -p "$OUT" + rm -vf "$OUT-lock-"* + rm -vrf "$OUT"/* + rm -vrf "$OUT"/.* + + cp -vrfHL "$sou"/. "$OUT" + echo "$sou" > "${storeLock}" + chown -cR ${user}:${group} "$OUT" + chmod -cR 1700 "$OUT" + ''; + + preStop = '' + rm -r "${storeLock}" + ''; }; + # 2. Prepare for mounting overlayfs "overlayfile-${user}-pre-mount" = let prev = "overlayfile-${user}-copy-check.service"; next = "run-overlay_files-${strings.escapeC ["-"] user}.mount"; - preMountScript = pkgs.writeShellScriptBin "overlay-${user}-pre-mount" '' + in { + description = "Create Upperdir and Workdir for overlay files of ${user}"; + before = [ next ]; + requiredBy = [ next ]; + after = [ prev ]; + bindsTo = [ prev ]; + partOf = [ prev ]; + wantedBy = [ "local-fs.target" ]; + + unitConfig.DefaultDependencies = "no"; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = "yes"; + }; + + script = '' mkdir -p ${upper_dir}/${user} mkdir -p ${work_dir}/${user} - chown ${user}:users ${upper_dir}/${user} + chown ${user}:${group} ${upper_dir}/${user} ''; - reMountScript = pkgs.writeShellScriptBin "overlay-${user}-pre-mount" '' + preStop = '' rm -rf ${upper_dir}/${user}/* rm -rf ${upper_dir}/${user}/.* rm -rf ${work_dir}/${user}/* rm -rf ${work_dir}/${user}/.* ''; - in { - path = with pkgs; [ coreutils ]; - unitConfig = { - Description = "Create Upperdir and Workdir for overlay files of ${user}"; - DefaultDependencies = "no"; - Before = next; - ConsistsOf= next; - Requires = prev; - After = prev; - PartOf = prev; - }; - - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = "yes"; - ExecStart = "${getExe preMountScript}"; - ExecStop = "${getExe reMountScript}"; - }; - - requiredBy = [ next ]; - wantedBy = [ next "local-fs.target" ]; }; + # 3. Mount overlayfs + + # 4. Make symlink to HOME "overlayfile-${user}-link-file" = let prev = "run-overlay_files-${strings.escapeC ["-"] user}.mount"; - linkScript = pkgs.writeShellScriptBin "overlay-${user}-link" '' - cp -vsrfp "/run/overlay_files/${user}"/. "${config.users.users.${user}.home}" - ''; in { - path = with pkgs; [ coreutils ]; - unitConfig = { - Description = "Link overlay files for ${user}"; - DefaultDependencies = "no"; - After = prev; - PartOf = prev; - Requires = prev; - }; + description = "Link overlay files for ${user}"; + after = [ prev ]; + partOf = [ prev ]; + bindsTo = [ prev ]; + wantedBy = [ "local-fs.target" ]; + + unitConfig.DefaultDependencies = "no"; serviceConfig = { Type = "oneshot"; RemainAfterExit = "yes"; - ExecStart = "${getExe linkScript}"; }; - wantedBy = [ "local-fs.target" ]; + script = '' + cp -vsrfp "/run/overlay_files/${user}"/. "${config.users.users.${user}.home}" + ''; }; } // sum )); diff --git a/modules/overlayfile/file-type.nix b/modules/overlayfile/file-type.nix index c6c8d06..5d4585e 100644 --- a/modules/overlayfile/file-type.nix +++ b/modules/overlayfile/file-type.nix @@ -1,59 +1,46 @@ -{ lib, pkgs }: # https://github.com/nix-community/home-manager/blob/master/modules/lib/file-type.nix -let - inherit (lib) hasPrefix literalExpression mkDefault mkIf mkOption removePrefix types; +{ name, config, lib, pkgs, ... }: +with lib; let inherit (import ./lib.nix { inherit lib; }) storeFileName; -in -types.attrsOf (types.submodule ( - { name, config, ... }: { - options = { - enable = mkOption { - type = types.bool; - default = true; - description = '' - Whether this file should be generated. This option allows specific - files to be disabled. - ''; - }; - - target = mkOption { - type = types.str; - defaultText = literalExpression ""; - description = '' - Path to target file. - ''; - }; +in { + options = { + enable = mkOption { + type = types.bool; + default = true; + description = '' + Whether this file should be generated. This option allows specific + files to be disabled. + ''; + }; - text = mkOption { - default = null; - type = types.nullOr types.lines; - description = '' - Text of the file. If this option is null then - - must be set. - ''; - }; + target = mkOption { + type = types.str; + default = name; + defaultText = literalExpression ""; + description = '' + Path to target file. + ''; + }; - source = mkOption { - type = types.path; - description = '' - Path of the source file or directory. If - - is non-null then this option will automatically point to a file - containing that text. - ''; - }; + text = mkOption { + type = types.lines; + default = ""; + description = '' + Text of the file. If this option is null then + + must be set. + ''; }; - config = { - target = mkDefault name; - source = mkIf (config.text != null) ( - mkDefault (pkgs.writeTextFile { - inherit (config) text; - executable = true; # can be null - name = storeFileName name; - }) - ); + source = mkOption { + type = types.path; + default = pkgs.writeText (storeFileName name) config.text; + description = '' + Path of the source file or directory. If + + is non-null then this option will automatically point to a file + containing that text. + ''; }; - } -)) \ No newline at end of file + }; +} \ No newline at end of file diff --git a/modules/overlayfile/lib.nix b/modules/overlayfile/lib.nix index 143ec41..2a45587 100644 --- a/modules/overlayfile/lib.nix +++ b/modules/overlayfile/lib.nix @@ -2,7 +2,7 @@ let inherit (lib) genList length lowerChars replaceStrings stringToCharacters upperChars; -in { +in rec { # Figures out a valid Nix store name for the given path. storeFileName = path: let @@ -20,4 +20,13 @@ in { safeName = replaceStrings unsafeInName (empties unsafeInName) path; in "overlay_" + safeName; + + sourceStorePath = file: + let + sourcePath = toString file.source; + sourceName = storeFileName (baseNameOf sourcePath); + in + if builtins.hasContext sourcePath + then file.source + else builtins.path { path = file.source; name = sourceName; }; } \ No newline at end of file diff --git a/modules/overlayfile/scripts/common.sh b/modules/overlayfile/scripts/common.sh deleted file mode 100644 index 0f08e9b..0000000 --- a/modules/overlayfile/scripts/common.sh +++ /dev/null @@ -1,82 +0,0 @@ -# This file contains a number of utilities for use by the home-manager tool and -# the generated Home Manager activation scripts. No guarantee is made about -# backwards or forward compatibility. -# - -# Sets up colors suitable for the `errorEcho`, `warnEcho`, and `noteEcho` -# functions. -# -# The check for terminal output and color support is heavily inspired by -# https://unix.stackexchange.com/a/10065. -# -# The setup respects the `NO_COLOR` environment variable. -function setupColors() { - normalColor="" - errorColor="" - warnColor="" - noteColor="" - - # Enable colors for terminals, and allow opting out. - if [[ ! -v NO_COLOR && -t 1 ]]; then - # See if it supports colors. - local ncolors - ncolors=$(tput colors 2> /dev/null || echo 0) - - if [[ -n "$ncolors" && "$ncolors" -ge 8 ]]; then - normalColor="$(tput sgr0)" - errorColor="$(tput bold)$(tput setaf 1)" - warnColor="$(tput setaf 3)" - noteColor="$(tput bold)$(tput setaf 6)" - fi - fi -} - -setupColors - -function errorEcho() { - echo "${errorColor}$*${normalColor}" -} - -function warnEcho() { - echo "${warnColor}$*${normalColor}" -} - -function noteEcho() { - echo "${noteColor}$*${normalColor}" -} - -function _i() { - local msgid="$1" - shift - - # shellcheck disable=2059 - printf "$(gettext "$msgid")\n" "$@" -} - -function _ip() { - local msgid="$1" - local msgidPlural="$2" - local count="$3" - shift 3 - - # shellcheck disable=2059 - printf "$(ngettext "$msgid" "$msgidPlural" "$count")\n" "$@" -} - -function _iError() { - echo -n "${errorColor}" - _i "$@" - echo -n "${normalColor}" -} - -function _iWarn() { - echo -n "${warnColor}" - _i "$@" - echo -n "${normalColor}" -} - -function _iNote() { - echo -n "${noteColor}" - _i "$@" - echo -n "${normalColor}" -} \ No newline at end of file