diff --git a/modules/misc/news.nix b/modules/misc/news.nix
index 27b1a5f7..708fd7f6 100644
--- a/modules/misc/news.nix
+++ b/modules/misc/news.nix
@@ -2029,6 +2029,23 @@ in
A new module is available: 'programs.foot'.
'';
}
+
+ {
+ time = "2021-04-13T07:19:36+00:00";
+ message = ''
+ mbsync channels no longer accepts the masterPattern or slavePattern
+ attribute keys. This is due to an upstream change.
+ They have been renamed: masterPattern -> farPattern, and
+ slavePattern -> nearPattern.
+ This is a stateful change, where the database file(s) used to keep track
+ of mail are silently upgraded once you upgrade both your configuration file
+ and the mbsync program.
+
+ Note that this change is non-reversible, meaning once you choose to switch to
+ near/farPattern, you can no longer use your previous slave/masterPattern
+ configuration file.
+ '';
+ }
];
};
}
diff --git a/modules/programs/mbsync-accounts.nix b/modules/programs/mbsync-accounts.nix
index cdd5997f..3f3f2d14 100644
--- a/modules/programs/mbsync-accounts.nix
+++ b/modules/programs/mbsync-accounts.nix
@@ -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 Patterns are specified, masterPattern
+ If Patterns are specified, farPattern
is interpreted as a prefix which is not matched against the patterns,
and is not affected by mailbox list overrides.
@@ -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.
If this is left as the default, then mbsync will default to the pattern
INBOX.
@@ -85,7 +85,7 @@ let
example = [ "INBOX" ];
description = ''
Instead of synchronizing just the mailboxes that
- match the masterPattern, use it as a prefix which is
+ match the farPattern, use it as a prefix which is
not matched against the patterns, and is not affected by mailbox list
overrides.
'';
diff --git a/modules/programs/mbsync.nix b/modules/programs/mbsync.nix
index 7d55c734..91e7d0f7 100644
--- a/modules/programs/mbsync.nix
+++ b/modules/programs/mbsync.nix
@@ -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
+ }
+ '';
+ };
+ }
+ ]);
}
diff --git a/tests/modules/programs/mbsync/mbsync-expected.conf b/tests/modules/programs/mbsync/mbsync-expected.conf
index 67229604..c1ca921a 100644
--- a/tests/modules/programs/mbsync/mbsync-expected.conf
+++ b/tests/modules/programs/mbsync/mbsync-expected.conf
@@ -16,30 +16,30 @@ Path /home/hm-user/Mail/hm-account/
SubFolders Verbatim
Channel emptyChannels-empty1
-Master :hm-account-remote:
-Slave :hm-account-local:
+Far :hm-account-remote:
+Near :hm-account-local:
Channel emptyChannels-empty2
-Master :hm-account-remote:
-Slave :hm-account-local:
+Far :hm-account-remote:
+Near :hm-account-local:
Channel hm-account-earlierPatternMatch
-Master :hm-account-remote:Label
-Slave :hm-account-local:SomethingUnderLabel
+Far :hm-account-remote:Label
+Near :hm-account-local:SomethingUnderLabel
Pattern ThingUnderLabel !NotThisMaildirThough "[Weird] Label?"
Channel hm-account-inbox
-Master :hm-account-remote:Inbox
-Slave :hm-account-local:Inbox
+Far :hm-account-remote:Inbox
+Near :hm-account-local:Inbox
Channel hm-account-patternMatch
-Master :hm-account-remote:Label
-Slave :hm-account-local:SomethingUnderLabel
+Far :hm-account-remote:Label
+Near :hm-account-local:SomethingUnderLabel
Pattern ThingUnderLabel !NotThisMaildirThough "[Weird] Label?"
Channel hm-account-strangeHostBoxName
-Master ":hm-account-remote:[Weird]/Label Mess"
-Slave :hm-account-local:[AnotherWeird]/Label
+Far ":hm-account-remote:[Weird]/Label Mess"
+Near :hm-account-local:[AnotherWeird]/Label
Group emptyChannels
Channel emptyChannels-empty1
@@ -68,12 +68,12 @@ Path /home/hm-user/Mail/hm@example.com/
SubFolders Verbatim
Channel inboxes-inbox1
-Master :hm@example.com-remote:Inbox1
-Slave :hm@example.com-local:Inboxes
+Far :hm@example.com-remote:Inbox1
+Near :hm@example.com-local:Inboxes
Channel inboxes-inbox2
-Master :hm@example.com-remote:Inbox2
-Slave :hm@example.com-local:Inboxes
+Far :hm@example.com-remote:Inbox2
+Near :hm@example.com-local:Inboxes
Group inboxes
Channel inboxes-inbox1
diff --git a/tests/modules/programs/mbsync/mbsync-master-slave-change.nix b/tests/modules/programs/mbsync/mbsync-master-slave-change.nix
new file mode 100644
index 00000000..96f02d90
--- /dev/null
+++ b/tests/modules/programs/mbsync/mbsync-master-slave-change.nix
@@ -0,0 +1,93 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ imports = [ ../../accounts/email-test-accounts.nix ];
+
+ test.asserts.warnings.expected = [
+ "mbsync channels no longer use masterPattern. Use farPattern in its place."
+ "mbsync channels no longer use slavePattern. Use nearPattern in its place."
+ ];
+
+ config = {
+ programs.mbsync = {
+ enable = true;
+ # programs.mbsync.groups and
+ # accounts.email.accounts..mbsync.groups should NOT be used at the
+ # same time.
+ # If they are, then the new version will take precendence.
+ groups.inboxes = {
+ "hm@example.com" = [ "Inbox1" "Inbox2" ];
+ hm-account = [ "Inbox" ];
+ };
+ };
+
+ accounts.email.accounts = {
+ "hm@example.com".mbsync = {
+ enable = true;
+ groups.inboxes = {
+ channels = {
+ inbox1 = {
+ farPattern = "Inbox1";
+ nearPattern = "Inboxes";
+ };
+ inbox2 = {
+ farPattern = "Inbox2";
+ nearPattern = "Inboxes";
+ };
+ };
+ };
+ };
+
+ hm-account.mbsync = {
+ enable = true;
+ groups.hm-account = {
+ channels.earlierPatternMatch = {
+ farPattern = "Label";
+ nearPattern = "SomethingUnderLabel";
+ patterns = [
+ "ThingUnderLabel"
+ "!NotThisMaildirThough"
+ ''"[Weird] Label?"''
+ ];
+ };
+ channels.inbox = {
+ farPattern = "Inbox";
+ nearPattern = "Inbox";
+ };
+ channels.strangeHostBoxName = {
+ farPattern = "[Weird]/Label Mess";
+ nearPattern = "[AnotherWeird]/Label";
+ };
+ channels.patternMatch = {
+ farPattern = "Label";
+ nearPattern = "SomethingUnderLabel";
+ patterns = [
+ "ThingUnderLabel"
+ "!NotThisMaildirThough"
+ ''"[Weird] Label?"''
+ ];
+ };
+ };
+ # No group should be printed.
+ groups.emptyGroup = { };
+ # Group should be printed, but left with default channels.
+ groups.emptyChannels = {
+ channels.empty1 = { };
+ channels.empty2 = { };
+ };
+ };
+ };
+
+ test.asserts.warnings.expected = [
+ "mbsync channels no longer use masterPattern. use farPattern in its place."
+ "mbsync channels no longer use slavePattern. Use nearPattern in its place."
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.mbsyncrc
+ assertFileContent home-files/.mbsyncrc ${./mbsync-expected.conf}
+ '';
+ };
+}
diff --git a/tests/modules/programs/mbsync/mbsync.nix b/tests/modules/programs/mbsync/mbsync.nix
index a6e555cd..d80421d6 100644
--- a/tests/modules/programs/mbsync/mbsync.nix
+++ b/tests/modules/programs/mbsync/mbsync.nix
@@ -24,12 +24,12 @@ with lib;
groups.inboxes = {
channels = {
inbox1 = {
- masterPattern = "Inbox1";
- slavePattern = "Inboxes";
+ farPattern = "Inbox1";
+ nearPattern = "Inboxes";
};
inbox2 = {
- masterPattern = "Inbox2";
- slavePattern = "Inboxes";
+ farPattern = "Inbox2";
+ nearPattern = "Inboxes";
};
};
};
@@ -39,8 +39,8 @@ with lib;
enable = true;
groups.hm-account = {
channels.earlierPatternMatch = {
- masterPattern = "Label";
- slavePattern = "SomethingUnderLabel";
+ farPattern = "Label";
+ nearPattern = "SomethingUnderLabel";
patterns = [
"ThingUnderLabel"
"!NotThisMaildirThough"
@@ -48,16 +48,16 @@ with lib;
];
};
channels.inbox = {
- masterPattern = "Inbox";
- slavePattern = "Inbox";
+ farPattern = "Inbox";
+ nearPattern = "Inbox";
};
channels.strangeHostBoxName = {
- masterPattern = "[Weird]/Label Mess";
- slavePattern = "[AnotherWeird]/Label";
+ farPattern = "[Weird]/Label Mess";
+ nearPattern = "[AnotherWeird]/Label";
};
channels.patternMatch = {
- masterPattern = "Label";
- slavePattern = "SomethingUnderLabel";
+ farPattern = "Label";
+ nearPattern = "SomethingUnderLabel";
patterns = [
"ThingUnderLabel"
"!NotThisMaildirThough"