isync/mbsync: replace master/slave with far/near (#1776)
* isync/mbsync: replace master/slave with far/near isync/mbsync: update tests to match new changes * isync/mbsync: use mkRenamedOptionModule to alert user to near/far change * isync/mbsync: use warnings to alert about master/slave far/near change Fix capitalization isync/mbsync: fix nitpicks * isync/mbsync: run format script * isync/mbsync: include new test for expected master/slave warnings * isync/mbsync: add news about changes
This commit is contained in:
parent
4f70f49cec
commit
64607f58b7
6 changed files with 239 additions and 87 deletions
|
|
@ -50,13 +50,13 @@ let
|
|||
'';
|
||||
};
|
||||
|
||||
masterPattern = mkOption {
|
||||
farPattern = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "[Gmail]/Sent Mail";
|
||||
description = ''
|
||||
IMAP4 patterns for which mailboxes on the remote mail server to sync.
|
||||
If <literal>Patterns</literal> are specified, <literal>masterPattern</literal>
|
||||
If <literal>Patterns</literal> are specified, <literal>farPattern</literal>
|
||||
is interpreted as a prefix which is not matched against the patterns,
|
||||
and is not affected by mailbox list overrides.
|
||||
</para><para>
|
||||
|
|
@ -65,14 +65,14 @@ let
|
|||
'';
|
||||
};
|
||||
|
||||
slavePattern = mkOption {
|
||||
nearPattern = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "Sent";
|
||||
description = ''
|
||||
Name for where mail coming from the master mail server will end up
|
||||
locally. The mailbox specified by the master's pattern will be placed
|
||||
in this directory.
|
||||
Name for where mail coming from the remote (far) mail server will end up
|
||||
locally. The mailbox specified by the far pattern will be placed in
|
||||
this directory.
|
||||
</para><para>
|
||||
If this is left as the default, then mbsync will default to the pattern
|
||||
<literal>INBOX</literal>.
|
||||
|
|
@ -85,7 +85,7 @@ let
|
|||
example = [ "INBOX" ];
|
||||
description = ''
|
||||
Instead of synchronizing <emphasis>just</emphasis> the mailboxes that
|
||||
match the <literal>masterPattern</literal>, use it as a prefix which is
|
||||
match the <literal>farPattern</literal>, use it as a prefix which is
|
||||
not matched against the patterns, and is not affected by mailbox list
|
||||
overrides.
|
||||
'';
|
||||
|
|
|
|||
|
|
@ -10,6 +10,24 @@ let
|
|||
mbsyncAccounts =
|
||||
filter (a: a.mbsync.enable) (attrValues config.accounts.email.accounts);
|
||||
|
||||
# Given a SINGLE group's channels attribute set, return true if ANY of the channel's
|
||||
# patterns use the invalidOption attribute set value name.
|
||||
channelInvalidOption = channels: invalidOption:
|
||||
any (c: c) (mapAttrsToList (c: hasAttr invalidOption) channels);
|
||||
|
||||
# Given a SINGLE account's groups attribute set, return true if ANY of the account's group's channel's patterns use the invalidOption attribute set value name.
|
||||
groupInvalidOption = groups: invalidOption:
|
||||
any (g: g) (mapAttrsToList (groupName: groupVals:
|
||||
channelInvalidOption groupVals.channels invalidOption) groups);
|
||||
|
||||
# Given all accounts (ensure that accounts passed in here ARE mbsync-using accounts)
|
||||
# return true if ANY of the account's groups' channels' patterns use the
|
||||
# invalidOption attribute set value name.
|
||||
accountInvalidOption = accounts: invalidOption:
|
||||
any (a: a)
|
||||
(map (account: groupInvalidOption account.mbsync.groups invalidOption)
|
||||
mbsyncAccounts);
|
||||
|
||||
genTlsConfig = tls:
|
||||
{
|
||||
SSLType = if !tls.enable then
|
||||
|
|
@ -22,10 +40,18 @@ let
|
|||
CertificateFile = toString tls.certificatesFile;
|
||||
};
|
||||
|
||||
masterSlaveMapping = {
|
||||
imports = [
|
||||
(mkRenamedOptionModule [ "programs" "mbsync" "masterSlaveMapping" ] [
|
||||
"programs"
|
||||
"mbsync"
|
||||
"nearFarMapping"
|
||||
])
|
||||
];
|
||||
|
||||
nearFarMapping = {
|
||||
none = "None";
|
||||
imap = "Master";
|
||||
maildir = "Slave";
|
||||
imap = "Far";
|
||||
maildir = "Near";
|
||||
both = "Both";
|
||||
};
|
||||
|
||||
|
|
@ -88,18 +114,18 @@ let
|
|||
genAccountWideChannel = account:
|
||||
with account;
|
||||
genSection "Channel ${name}" ({
|
||||
Master = ":${name}-remote:";
|
||||
Slave = ":${name}-local:";
|
||||
Far = ":${name}-remote:";
|
||||
Near = ":${name}-local:";
|
||||
Patterns = mbsync.patterns;
|
||||
Create = masterSlaveMapping.${mbsync.create};
|
||||
Remove = masterSlaveMapping.${mbsync.remove};
|
||||
Expunge = masterSlaveMapping.${mbsync.expunge};
|
||||
Create = nearFarMapping.${mbsync.create};
|
||||
Remove = nearFarMapping.${mbsync.remove};
|
||||
Expunge = nearFarMapping.${mbsync.expunge};
|
||||
SyncState = "*";
|
||||
} // mbsync.extraConfig.channel) + "\n";
|
||||
|
||||
# Given the attr set of groups, return a string of channels that will direct
|
||||
# mail to the proper directories, according to the pattern used in channel's
|
||||
# master pattern definition.
|
||||
# "far" pattern definition.
|
||||
genGroupChannelConfig = storeName: groups:
|
||||
let
|
||||
# Given the name of the group this channel is part of and the channel
|
||||
|
|
@ -118,8 +144,8 @@ let
|
|||
else
|
||||
"";
|
||||
in genSection "Channel ${groupName}-${channel.name}" ({
|
||||
Master = ":${storeName}-remote:${channel.masterPattern}";
|
||||
Slave = ":${storeName}-local:${channel.slavePattern}";
|
||||
Far = ":${storeName}-remote:${channel.farPattern}";
|
||||
Near = ":${storeName}-local:${channel.nearPattern}";
|
||||
} // channel.extraConfig) + genChannelPatterns channel.patterns;
|
||||
# Given the group name, and a attr set of channels within that group,
|
||||
# Generate a list of strings for each channels' configuration.
|
||||
|
|
@ -206,50 +232,66 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = let
|
||||
checkAccounts = pred: msg:
|
||||
let badAccounts = filter pred mbsyncAccounts;
|
||||
in {
|
||||
assertion = badAccounts == [ ];
|
||||
message = "mbsync: ${msg} for accounts: "
|
||||
+ concatMapStringsSep ", " (a: a.name) badAccounts;
|
||||
};
|
||||
in [
|
||||
(checkAccounts (a: a.maildir == null) "Missing maildir configuration")
|
||||
(checkAccounts (a: a.imap == null) "Missing IMAP configuration")
|
||||
(checkAccounts (a: a.passwordCommand == null) "Missing passwordCommand")
|
||||
(checkAccounts (a: a.userName == null) "Missing username")
|
||||
];
|
||||
config = mkIf cfg.enable (mkMerge [
|
||||
{
|
||||
assertions = let
|
||||
checkAccounts = pred: msg:
|
||||
let badAccounts = filter pred mbsyncAccounts;
|
||||
in {
|
||||
assertion = badAccounts == [ ];
|
||||
message = "mbsync: ${msg} for accounts: "
|
||||
+ concatMapStringsSep ", " (a: a.name) badAccounts;
|
||||
};
|
||||
in [
|
||||
(checkAccounts (a: a.maildir == null) "Missing maildir configuration")
|
||||
(checkAccounts (a: a.imap == null) "Missing IMAP configuration")
|
||||
(checkAccounts (a: a.passwordCommand == null) "Missing passwordCommand")
|
||||
(checkAccounts (a: a.userName == null) "Missing username")
|
||||
];
|
||||
}
|
||||
|
||||
home.packages = [ cfg.package ];
|
||||
(mkIf (accountInvalidOption mbsyncAccounts "masterPattern") {
|
||||
warnings = [
|
||||
"mbsync channels no longer use masterPattern. Use farPattern in its place."
|
||||
];
|
||||
})
|
||||
|
||||
programs.notmuch.new.ignore = [ ".uidvalidity" ".mbsyncstate" ];
|
||||
(mkIf (accountInvalidOption mbsyncAccounts "slavePattern") {
|
||||
warnings = [
|
||||
"mbsync channels no longer use slavePattern. Use nearPattern in its place."
|
||||
];
|
||||
})
|
||||
|
||||
home.file.".mbsyncrc".text = let
|
||||
accountsConfig = map genAccountConfig mbsyncAccounts;
|
||||
# Only generate this kind of Group configuration if there are ANY accounts
|
||||
# that do NOT have a per-account groups/channels option(s) specified.
|
||||
groupsConfig =
|
||||
if any (account: account.mbsync.groups == { }) mbsyncAccounts then
|
||||
mapAttrsToList genGroupConfig cfg.groups
|
||||
else
|
||||
[ ];
|
||||
in ''
|
||||
# Generated by Home Manager.
|
||||
{
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
''
|
||||
+ concatStringsSep "\n" (optional (cfg.extraConfig != "") cfg.extraConfig)
|
||||
+ concatStringsSep "\n\n" accountsConfig
|
||||
+ concatStringsSep "\n" groupsConfig;
|
||||
programs.notmuch.new.ignore = [ ".uidvalidity" ".mbsyncstate" ];
|
||||
|
||||
home.activation = mkIf (mbsyncAccounts != [ ]) {
|
||||
createMaildir =
|
||||
hm.dag.entryBetween [ "linkGeneration" ] [ "writeBoundary" ] ''
|
||||
$DRY_RUN_CMD mkdir -m700 -p $VERBOSE_ARG ${
|
||||
concatMapStringsSep " " (a: a.maildir.absPath) mbsyncAccounts
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
home.file.".mbsyncrc".text = let
|
||||
accountsConfig = map genAccountConfig mbsyncAccounts;
|
||||
# Only generate this kind of Group configuration if there are ANY accounts
|
||||
# that do NOT have a per-account groups/channels option(s) specified.
|
||||
groupsConfig =
|
||||
if any (account: account.mbsync.groups == { }) mbsyncAccounts then
|
||||
mapAttrsToList genGroupConfig cfg.groups
|
||||
else
|
||||
[ ];
|
||||
in ''
|
||||
# Generated by Home Manager.
|
||||
|
||||
''
|
||||
+ concatStringsSep "\n" (optional (cfg.extraConfig != "") cfg.extraConfig)
|
||||
+ concatStringsSep "\n\n" accountsConfig
|
||||
+ concatStringsSep "\n" groupsConfig;
|
||||
|
||||
home.activation = mkIf (mbsyncAccounts != [ ]) {
|
||||
createMaildir =
|
||||
hm.dag.entryBetween [ "linkGeneration" ] [ "writeBoundary" ] ''
|
||||
$DRY_RUN_CMD mkdir -m700 -p $VERBOSE_ARG ${
|
||||
concatMapStringsSep " " (a: a.maildir.absPath) mbsyncAccounts
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue