Subject: bug#37926: [PATCH] Unify Gnus select methods

From: [email-masked]
Date: Fri, 25 Oct 2019 16:08:40 -0400

>From d4654ad8f3412c79fa7d29427e66d2b964d5e191 Mon Sep 17 00:00:00 2001
From: dickmao <none>
Date: Mon, 30 Sep 2019 09:13:38 -0400
Subject: [PATCH] Unify gnus select methods into one defcustom

* doc/emacs/misc.texi (Gnus Startup): doc
* doc/misc/auth.texi (Multiple GMail accounts with Gnus): doc
* doc/misc/gnus-faq.texi (FAQ 3-1): doc
* doc/misc/gnus.texi (Starting Up): doc
* doc/misc/mh-e.texi (Procmail): doc
* etc/gnus/news-server.ast (Setting up the news server name and port number): doc
* lisp/gnus/gnus-agent.el (gnus-agentize): use gnus-select-methods instead of consing
* lisp/gnus/gnus-int.el (gnus-start-news-server): rationalize an obsolete function
* lisp/gnus/gnus-msg.el (gnus-post-method): use gnus-select-methods instead of consing
* lisp/gnus/gnus-start.el (gnus-check-new-newsgroups): doc
(gnus-ask-server-for-new-groups): use gnus-select-methods instead of consing
(gnus-get-unread-articles): use gnus-select-methods instead of consing
(gnus-method-rank): primary and secondary labels can be treated the same
(gnus-read-active-file): use gnus-select-methods instead of consing
(gnus-read-all-descriptions-files): use gnus-select-methods instead of consing
* lisp/gnus/gnus.el (gnus-secondary-select-methods, gnus-select-method): obsolesce and modify defcustom ':set' to funnel to gnus-select-methods
* lisp/gnus/nnir.el: doc
* lisp/gnus/nnmail.el (nnmail-cache-primary-mail-backend): use gnus-select-methods instead of consing
* test/lisp/gnus/gnus-test-select-methods.el: test gnus-select-methods
---
 doc/emacs/misc.texi                        |   3 +-
 doc/misc/auth.texi                         |  10 +-
 doc/misc/gnus-faq.texi                     |  18 +--
 doc/misc/gnus.texi                         |  95 ++++++----------
 doc/misc/mh-e.texi                         |   2 +-
 etc/gnus/news-server.ast                   |   4 +-
 lisp/gnus/gnus-agent.el                    |   2 +-
 lisp/gnus/gnus-int.el                      | 125 ++++++++++-----------
 lisp/gnus/gnus-msg.el                      |   3 +-
 lisp/gnus/gnus-start.el                    |  60 +++++-----
 lisp/gnus/gnus.el                          |  28 +++++
 lisp/gnus/nnir.el                          |   2 +-
 lisp/gnus/nnmail.el                        |   2 +-
 test/lisp/gnus/gnus-test-select-methods.el | 108 ++++++++++++++++++
 14 files changed, 277 insertions(+), 185 deletions(-)
 create mode 100644 test/lisp/gnus/gnus-test-select-methods.el

diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index 63b65e779c..2617297591 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -97,8 +97,7 @@ Gnus Startup
   If your system does not have a default news server, or if you wish
 to use Gnus for reading email, then before invoking @kbd{M-x gnus} you
 need to tell Gnus where to get news and/or mail.  To do this,
-customize the variables @code{gnus-select-method} and/or
-@code{gnus-secondary-select-methods}.
+customize the variable @code{gnus-select-methods}.
 @iftex
 See the Gnus manual for details.
 @end iftex
diff --git a/doc/misc/auth.texi b/doc/misc/auth.texi
index 93a301dcb1..dd6d25ba96 100644
--- a/doc/misc/auth.texi
+++ b/doc/misc/auth.texi
@@ -258,14 +258,14 @@ Multiple GMail accounts with Gnus
 @chapter Multiple GMail accounts with Gnus
 
 For multiple GMail accounts with Gnus, you have to make two nnimap
-entries in your @code{gnus-secondary-select-methods} with distinct
+entries in your @code{gnus-select-methods} with distinct
 names:
 
 @example
-(setq gnus-secondary-select-methods '((nnimap "gmail"
-                                         (nnimap-address "imap.gmail.com"))
-                                      (nnimap "gmail2"
-                                         (nnimap-address "imap.gmail.com"))))
+(setq gnus-select-methods '((nnimap "gmail"
+                               (nnimap-address "imap.gmail.com"))
+                            (nnimap "gmail2"
+                               (nnimap-address "imap.gmail.com"))))
 @end example
 
 Your netrc entries will then be:
diff --git a/doc/misc/gnus-faq.texi b/doc/misc/gnus-faq.texi
index b0dc9c3ba3..0d8f37b0c5 100644
--- a/doc/misc/gnus-faq.texi
+++ b/doc/misc/gnus-faq.texi
@@ -363,7 +363,7 @@ FAQ 3-1
 first start, put those lines in @file{~/.gnus.el}:
 
 @example
-(setq gnus-select-method '(nntp "news.yourprovider.net"))
+(setq gnus-select-methods '((nntp "news.yourprovider.net")))
 (setq user-mail-address "you@@yourprovider.net")
 (setq user-full-name "Your Name")
 @end example
@@ -477,13 +477,13 @@ FAQ 3-6
 @subsubheading Answer
 
 Of course. You can specify more sources for articles in the
-variable gnus-secondary-select-methods. Add something like
+variable gnus-select-methods. Add something like
 this in @file{~/.gnus.el}:
 
 @example
-(add-to-list 'gnus-secondary-select-methods
+(add-to-list 'gnus-select-methods
              '(nntp "news.yourSecondProvider.net"))
-(add-to-list 'gnus-secondary-select-methods
+(add-to-list 'gnus-select-methods
              '(nntp "news.yourThirdProvider.net"))
 @end example
 @noindent
@@ -499,7 +499,7 @@ FAQ 3-7
 nnspool, so you want this:
 
 @example
-(add-to-list 'gnus-secondary-select-methods '(nnspool ""))
+(add-to-list 'gnus-select-methods '(nnspool ""))
 @end example
 @noindent
 
@@ -514,7 +514,7 @@ FAQ 3-7
 want something different, change the line above to something like this:
 
 @example
-(add-to-list 'gnus-secondary-select-methods
+(add-to-list 'gnus-select-methods
              '(nnspool ""
                        (nnspool-directory "/usr/local/myspoolddir")))
 @end example
@@ -552,14 +552,14 @@ FAQ 3-8
 choice for you.  To use nnml add the following to @file{~/.gnus.el}:
 
 @example
-(add-to-list 'gnus-secondary-select-methods '(nnml ""))
+(add-to-list 'gnus-select-methods '(nnml ""))
 @end example
 @noindent
 
 As you might have guessed, if you want nnfolder, it's
 
 @example
-(add-to-list 'gnus-secondary-select-methods '(nnfolder ""))
+(add-to-list 'gnus-select-methods '(nnfolder ""))
 @end example
 @noindent
 
@@ -656,7 +656,7 @@ FAQ 3-9
 about the server there.
 
 @example
-(add-to-list 'gnus-secondary-select-methods
+(add-to-list 'gnus-select-methods
              '(nnimap "Give the baby a name"
                       (nnimap-address "imap.yourProvider.net")
                       (nnimap-port 143)
diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi
index 8ab1cf9f68..46560de977 100644
--- a/doc/misc/gnus.texi
+++ b/doc/misc/gnus.texi
@@ -957,7 +957,7 @@ Starting Up
 If your system administrator has set things up properly, starting Gnus
 and reading news is extremely easy---you just type @kbd{M-x gnus} in
 your Emacs.  If not, you should customize the variable
-@code{gnus-select-method} as described in @ref{Finding the News}.  For a
+@code{gnus-select-methods} as described in @ref{Finding the News}.  For a
 minimal setup for posting should also customize the variables
 @code{user-full-name} and @code{user-mail-address}.
 
@@ -998,25 +998,23 @@ Finding the News
 do many other neat things.  @xref{Server Buffer}.
 @xref{Foreign Groups}.  @xref{Agent Basics}.
 
-@vindex gnus-select-method
+@vindex gnus-select-methods
 @c @head
-The @code{gnus-select-method} variable says where Gnus should look for
-news.  This variable should be a list where the first element says
-@dfn{how} and the second element says @dfn{where}.  This method is your
-native method.  All groups not fetched with this method are
-secondary or foreign groups.
+The @code{gnus-select-methods} should be a list of @xref{Select Methods}.
+A select method is a list where the first element says @dfn{how} and the
+second element says @dfn{where}.
 
 For instance, if the @samp{news.somewhere.edu} @acronym{NNTP} server is where
 you want to get your daily dosage of news from, you'd say:
 
 @lisp
-(setq gnus-select-method '(nntp "news.somewhere.edu"))
+(setq gnus-select-methods '((nntp "news.somewhere.edu")))
 @end lisp
 
 If you want to read directly from the local spool, say:
 
 @lisp
-(setq gnus-select-method '(nnspool ""))
+(setq gnus-select-methods '((nnspool "")))
 @end lisp
 
 If you can use a local spool, you probably should, as it will almost
@@ -1043,25 +1041,6 @@ Finding the News
 to any of the groups you want to.  This also makes @file{.newsrc}
 maintenance much tidier.  @xref{Foreign Groups}.
 
-@vindex gnus-secondary-select-methods
-@c @head
-A slightly different approach to foreign groups is to set the
-@code{gnus-secondary-select-methods} variable.  The select methods
-listed in this variable are in many ways just as native as the
-@code{gnus-select-method} server.  They will also be queried for active
-files during startup (if that's required), and new newsgroups that
-appear on these servers will be subscribed (or not) just as native
-groups are.
-
-For instance, if you use the @code{nnmbox} back end to read your mail,
-you would typically set this variable to
-
-@lisp
-(setq gnus-secondary-select-methods '((nnmbox "")))
-@end lisp
-
-
-
 @node The Server is Down
 @section The Server is Down
 @cindex server errors
@@ -1335,14 +1314,14 @@ Changing Servers
 very flaky and you want to use another.
 
 Changing the server is pretty easy, right?  You just change
-@code{gnus-select-method} to point to the new server?
+@code{gnus-select-methods} to point to the new server?
 
 @emph{Wrong!}
 
 Article numbers are not (in any way) kept synchronized between different
 @acronym{NNTP} servers, and the only way Gnus keeps track of what articles
 you have read is by keeping track of article numbers.  So when you
-change @code{gnus-select-method}, your @file{.newsrc} file becomes
+change @code{gnus-select-methods}, your @file{.newsrc} file becomes
 worthless.
 
 @findex gnus-group-clear-data-on-native-groups
@@ -2516,8 +2495,8 @@ Foreign Groups
 @cindex foreign groups
 
 If you recall how to subscribe to servers (@pxref{Finding the News})
-you will remember that @code{gnus-secondary-select-methods} and
-@code{gnus-select-method} let you write a definition in Emacs Lisp of
+you will remember that @code{gnus-select-methods}
+lets you write a definition in Emacs Lisp of
 what servers you want to see when you start up.  The alternate
 approach is to use foreign servers and groups.  ``Foreign'' here means
 they are not coming from the select methods.  All foreign server
@@ -10756,7 +10735,7 @@ Mail Group Commands
 @code{Newsgroups} header in them, but not always.  This command
 (@code{gnus-summary-article-posted-p}) will try to fetch the current
 article from your news server (or rather, from
-@code{gnus-refer-article-method} or @code{gnus-select-method}) and will
+@code{gnus-refer-article-method} or @code{gnus-select-methods}) and will
 report back whether it found the article or not.  Even if it says that
 it didn't find the article, it may have been posted anyway---mail
 propagation is much faster than news propagation, and the news copy may
@@ -13417,14 +13396,14 @@ Example Methods
 an indirect connection:
 
 @lisp
-(setq gnus-select-method
-      '(nntp "indirect"
+(setq gnus-select-methods
+      '((nntp "indirect"
              (nntp-address "news.server.example")
              (nntp-via-user-name "intermediate_user_name")
              (nntp-via-address "intermediate.host.example")
              (nntp-via-rlogin-command "ssh")
              (nntp-via-rlogin-command-switches ("-C"))
-             (nntp-open-connection-function nntp-open-via-rlogin-and-netcat)))
+             (nntp-open-connection-function nntp-open-via-rlogin-and-netcat))))
 @end lisp
 
 This means that you have to have set up @code{ssh-agent} correctly to
@@ -13510,7 +13489,7 @@ Servers and Methods
 @subsection Servers and Methods
 
 Wherever you would normally use a select method
-(e.g., @code{gnus-secondary-select-method}, in the group select method,
+(e.g., @code{gnus-select-methods}, in the group select method,
 when browsing a foreign server) you can use a virtual server name
 instead.  This could potentially save lots of typing.  And it's nice all
 over.
@@ -13796,11 +13775,11 @@ NNTP
 value, and Gnus never uses article numbers.  For example:
 
 @lisp
-(setq gnus-select-method
-      '(nntp "newszilla"
-             (nntp-address "newszilla.example.com")
-             (nntp-xref-number-is-evil t)
-             @dots{}))
+(setq gnus-select-methods
+      '((nntp "newszilla"
+              (nntp-address "newszilla.example.com")
+              (nntp-xref-number-is-evil t)
+              @dots{})))
 @end lisp
 
 The default value of this server variable is @code{nil}.
@@ -14244,8 +14223,8 @@ Connecting to an IMAP Server
 something like:
 
 @example
-(setq gnus-select-method
-      '(nnimap "imap.gmail.com"))
+(setq gnus-select-methods
+      '((nnimap "imap.gmail.com")))
 @end example
 
 You'll be prompted for a user name and password.  If you grow tired of
@@ -14516,14 +14495,14 @@ Getting Started Reading Mail
 @subsection Getting Started Reading Mail
 
 It's quite easy to use Gnus to read your new mail.  You just plonk the
-mail back end of your choice into @code{gnus-secondary-select-methods},
+mail back end of your choice into @code{gnus-select-methods},
 and things will happen automatically.
 
 For instance, if you want to use @code{nnml} (which is a ``one file per
 mail'' back end), you could put the following in your @file{~/.gnus.el} file:
 
 @lisp
-(setq gnus-secondary-select-methods '((nnml "")))
+(setq gnus-select-methods '((nnml "")))
 @end lisp
 
 Now, the next time you start Gnus, this back end will be queried for new
@@ -17715,15 +17694,10 @@ The Empty Backend
 @cindex nnnil
 
 @code{nnnil} is a backend that can be used as a placeholder if you
-have to specify a backend somewhere, but don't really want to.  The
-classical example is if you don't want to have a primary select
-methods, but want to only use secondary ones:
+have to specify a backend somewhere, but don't really want to:
 
 @lisp
-(setq gnus-select-method '(nnnil ""))
-(setq gnus-secondary-select-methods
-      '((nnimap "foo")
-        (nnml "")))
+(setq gnus-select-methods '((nnnil "")))
 @end lisp

@@ -18011,7 +17985,7 @@ Running NNDiary
 
   Finally, you may add a permanent @code{nndiary} virtual server
 (something like @code{(nndiary "diary")} should do) to your
-@code{gnus-secondary-select-methods}.
+@code{gnus-select-methods}.
 
   Hopefully, almost everything (see the TODO section in
 @file{nndiary.el}) will work as expected when you restart Gnus: in
@@ -19354,14 +19328,14 @@ Example Setup
 @lisp
 ;; @r{Define how Gnus is to fetch news.  We do this over @acronym{NNTP}}
 ;; @r{from your ISP's server.}
-(setq gnus-select-method '(nntp "news.your-isp.com"))
+(setq gnus-select-methods '((nntp "news.your-isp.com")))
 
 ;; @r{Define how Gnus is to read your mail.  We read mail from}
 ;; @r{your ISP's @acronym{POP} server.}
 (setq mail-sources '((pop :server "pop.your-isp.com")))
 
 ;; @r{Say how Gnus is to store the mail.  We use nnml groups.}
-(setq gnus-secondary-select-methods '((nnml "")))
+(push '(nnml "") gnus-select-methods)
 
 ;; @r{Make Gnus into an offline newsreader.}
 ;; (gnus-agentize) ; @r{The obsolete setting.}
@@ -21250,7 +21224,7 @@ Associating Engines
 named @code{home} you can use
 
 @lisp
-(setq gnus-secondary-select-methods
+(setq gnus-select-methods
       '((nnml "home"
          (nnimap-address "localhost")
          (nnir-search-engine namazu))))
@@ -28482,11 +28456,8 @@ Oort Gnus
 @item
 @code{gnus-agent}
 
-The Gnus Agent has seen a major updated and is now enabled by default,
-and all nntp and nnimap servers from @code{gnus-select-method} and
-@code{gnus-secondary-select-method} are agentized by default.  Earlier
-only the server in @code{gnus-select-method} was agentized by the
-default, and the agent was disabled by default.  When the agent is
+The Gnus Agent now agentizes all nnimap and nntp entries in
+@code{gnus-select-methods} by default.  When the agent is
 enabled, headers are now also retrieved from the Agent cache instead
 of the back ends when possible.  Earlier this only happened in the
 unplugged state.  You can enroll or remove servers with @kbd{J a} and
diff --git a/doc/misc/mh-e.texi b/doc/misc/mh-e.texi
index 9d249fb0ec..ef95fe451c 100644
--- a/doc/misc/mh-e.texi
+++ b/doc/misc/mh-e.texi
@@ -8635,7 +8635,7 @@ Procmail
 @key{RET} nnml @key{RET}}.
 
 @vtable @code
-@item gnus-secondary-select-methods
+@item gnus-select-methods
 Select the @samp{nnml} value. This select method uses directories for
 folders and individual files for messages, just like MH@. You do not
 have to set an address.
diff --git a/etc/gnus/news-server.ast b/etc/gnus/news-server.ast
index df0bab4519..8da881ccbe 100644
--- a/etc/gnus/news-server.ast
+++ b/etc/gnus/news-server.ast
@@ -5,7 +5,7 @@
 @variable server :string (or (gnus-getenv-nntpserver) "your-server-here")
 @variable port :number 119
 @validate (or (assistant-validate-connect-to-server server port) (y-or-n-p "Do you want to use the server anyway, although you can't confirm it's valid?"))
-@result gnus-select-method (list 'nntp server (list 'nntp-server port))
+@result gnus-select-methods (list (list 'nntp server (list 'nntp-server port)))
 @text
 Usenet news is usually read from your Internet service provider's news
 server.  If you don't know the name of this server, contact your ISP.
@@ -20,7 +20,7 @@ Port number: @variable{port}
 
 @node User name and password
 @type interstitial
-@next 
+@next
 (if (assistant-password-required-p)
     "Enter user name and password"
   "Want user name and password?")
diff --git a/lisp/gnus/gnus-agent.el b/lisp/gnus/gnus-agent.el
index 1f25255278..7ed11d5a7b 100644
--- a/lisp/gnus/gnus-agent.el
+++ b/lisp/gnus/gnus-agent.el
@@ -639,7 +639,7 @@ gnus-agentize
 	   (push (gnus-method-to-server method)
 		 gnus-agent-covered-methods)
 	   (setq gnus-agent-method-p-cache nil))))
-     (cons gnus-select-method gnus-secondary-select-methods))
+     gnus-select-methods)
     (gnus-agent-write-servers)))
 
 (defun gnus-agent-queue-setup (&optional group-name)
diff --git a/lisp/gnus/gnus-int.el b/lisp/gnus/gnus-int.el
index 0abbfe6720..90d30ed483 100644
--- a/lisp/gnus/gnus-int.el
+++ b/lisp/gnus/gnus-int.el
@@ -103,73 +103,66 @@ gnus-status-message
 (defun gnus-start-news-server (&optional confirm)
   "Open a method for getting news.
 If CONFIRM is non-nil, the user will be asked for an NNTP server."
-  (let (how)
-    (if gnus-current-select-method
-	;; Stream is already opened.
-	nil
-      ;; Open NNTP server.
-      (when confirm
-	;; Read server name with completion.
-	(setq gnus-nntp-server
-	      (gnus-completing-read "NNTP server"
-                                    (cons gnus-nntp-server
-					  (if (boundp 'gnus-secondary-servers)
-					      gnus-secondary-servers))
-                                    nil gnus-nntp-server)))
-
-      (when (and gnus-nntp-server
-		 (stringp gnus-nntp-server)
-		 (not (string= gnus-nntp-server "")))
-	(setq gnus-select-method
-	      (cond ((or (string= gnus-nntp-server "")
-			 (string= gnus-nntp-server "::"))
-		     (list 'nnspool (system-name)))
-		    ((string-match "^:" gnus-nntp-server)
-		     (list 'nnmh gnus-nntp-server
-			   (list 'nnmh-directory
-				 (file-name-as-directory
-				  (expand-file-name
-				   (substring gnus-nntp-server 1) "~/")))
-			   (list 'nnmh-get-new-mail nil)))
-		    (t
-		     (list 'nntp gnus-nntp-server)))))
-
-      (setq how (car gnus-select-method))
-      (cond
-       ((eq how 'nnspool)
-	(require 'nnspool)
-	(gnus-message 5 "Looking up local news spool..."))
-       ((eq how 'nnmh)
-	(require 'nnmh)
-	(gnus-message 5 "Looking up mh spool..."))
-       (t
-	(require 'nntp)))
-      (setq gnus-current-select-method gnus-select-method)
-      (gnus-run-hooks 'gnus-open-server-hook)
+  (unless gnus-current-select-method
+    (when confirm
+      ;; Read server name with completion.
+      (setq gnus-nntp-server
+            (gnus-completing-read "NNTP server"
+                                  (cons gnus-nntp-server
+                                        (if (boundp 'gnus-secondary-servers)
+                                            gnus-secondary-servers))
+                                  nil gnus-nntp-server)))
+    (when (and (stringp gnus-nntp-server)
+               (not (zerop (length gnus-nntp-server))))
+      ;; this will also assign the obsolete variable `gnus-select-method'
+      (custom-set-variables
+       `(gnus-select-methods
+         (quote (,(cond ((string= gnus-nntp-server "::")
+                         (list 'nnspool (system-name)))
+                        ((string-match "^:" gnus-nntp-server)
+                         (list 'nnmh gnus-nntp-server
+                               (list 'nnmh-directory
+                                     (file-name-as-directory
+                                      (expand-file-name
+                                       (substring gnus-nntp-server 1) "~/")))
+                               (list 'nnmh-get-new-mail nil)))
+                        (t
+                         (list 'nntp gnus-nntp-server))))))))
+    (setq gnus-current-select-method gnus-select-method)
+    (cl-case (car gnus-select-method)
+      ('nnspool
+       (require 'nnspool)
+       (gnus-message 5 "Looking up local news spool..."))
+      ('nnmh
+       (require 'nnmh)
+       (gnus-message 5 "Looking up mh spool..."))
+      (t
+       (require 'nntp)))
+    (gnus-run-hooks 'gnus-open-server-hook)
+
+    ;; Partially validate agent covered methods now that the
+    ;; gnus-select-method is known.
+
+    (if gnus-agent
+        ;; NOTE: This is here for one purpose only.  By validating
+        ;; the current select method, it converts the old 5.10.3,
+        ;; and earlier, format to the current format.  That enables
+        ;; the agent code within gnus-open-server to function
+        ;; correctly.
+        (gnus-agent-read-servers-validate-native gnus-select-method))
 
-      ;; Partially validate agent covered methods now that the
-      ;; gnus-select-method is known.
-
-      (if gnus-agent
-          ;; NOTE: This is here for one purpose only.  By validating
-          ;; the current select method, it converts the old 5.10.3,
-          ;; and earlier, format to the current format.  That enables
-          ;; the agent code within gnus-open-server to function
-          ;; correctly.
-          (gnus-agent-read-servers-validate-native gnus-select-method))
-
-      (or
-       ;; gnus-open-server-hook might have opened it
-       (gnus-server-opened gnus-select-method)
-       (gnus-open-server gnus-select-method)
-       gnus-batch-mode
-       (gnus-y-or-n-p
-	(format-message
-	 "%s (%s) open error: `%s'.  Continue? "
-	 (car gnus-select-method) (cadr gnus-select-method)
-	 (gnus-status-message gnus-select-method)))
-       (gnus-error 1 "Couldn't open server on %s"
-		   (nth 1 gnus-select-method))))))
+    (or
+     ;; gnus-open-server-hook might have opened it
+     (gnus-server-opened gnus-select-method)
+     (gnus-open-server gnus-select-method)
+     gnus-batch-mode
+     (gnus-y-or-n-p
+      (format-message
+       "%s (%s) open error: `%s'.  Continue? "
+       (car gnus-select-method) (cadr gnus-select-method)
+       (gnus-status-message gnus-select-method)))
+     (gnus-error 1 "Couldn't open server on %s"
+                 (nth 1 gnus-select-method)))))
 
 (defun gnus-check-group (group)
   "Try to make sure that the server where GROUP exists is alive."
diff --git a/lisp/gnus/gnus-msg.el b/lisp/gnus/gnus-msg.el
index 10793455a5..ee5780e3f2 100644
--- a/lisp/gnus/gnus-msg.el
+++ b/lisp/gnus/gnus-msg.el
@@ -1054,10 +1054,9 @@ gnus-post-method
 		 (if (listp (car gnus-post-method))
 		     gnus-post-method
 		   (list gnus-post-method)))
-	       gnus-secondary-select-methods
+	       gnus-select-methods
 	       (mapcar 'cdr gnus-server-alist)
 	       (mapcar 'car gnus-opened-servers)
-	       (list gnus-select-method)
 	       (list group-method)))
 	     method-alist post-methods method)
 	;; Weed out all mail methods.
diff --git a/lisp/gnus/gnus-start.el b/lisp/gnus/gnus-start.el
index e142c438ee..04a6f33149 100644
--- a/lisp/gnus/gnus-start.el
+++ b/lisp/gnus/gnus-start.el
@@ -108,7 +108,7 @@ gnus-check-new-newsgroups
 or killed.
 
 When any of the following are true, `gnus-find-new-newsgroups' will instead
-ask the servers (primary, secondary, and archive servers) to list new
+ask the servers (including the archive server) to list new
 groups since the last time it checked:
   1. This variable is `ask-server'.
   2. This variable is a list of select methods (see below).
@@ -120,8 +120,7 @@ gnus-check-new-newsgroups
 longer necessary, so you could safely set `gnus-save-killed-list' to nil.
 
 This variable can be a list of select methods which Gnus will query with
-the `ask-server' method in addition to the primary, secondary, and archive
-servers.
+the `ask-server' method in addition to the archive server.
 
 E.g.:
   (setq gnus-check-new-newsgroups
@@ -1165,21 +1164,18 @@ gnus-matches-options-n
 (defun gnus-ask-server-for-new-groups ()
   (let* ((new-date (message-make-date))
 	 (date (or gnus-newsrc-last-checked-date new-date))
-	 (methods (cons gnus-select-method
-			(nconc
-			 (when (gnus-archive-server-wanted-p)
-			   (list "archive"))
-			 (append
-			  (and (consp gnus-check-new-newsgroups)
-			       gnus-check-new-newsgroups)
-			  gnus-secondary-select-methods))))
+	 (methods (nconc
+                   (when (gnus-archive-server-wanted-p)
+                     (list "archive"))
+                   (append
+                    (and (consp gnus-check-new-newsgroups)
+                         gnus-check-new-newsgroups)
+                    gnus-select-methods)))
 	 (groups 0)
 	 group new-newsgroups got-new method hashtb
 	 gnus-override-subscribe-method)
     (unless gnus-killed-hashtb
       (gnus-make-hashtable-from-killed))
-    ;; Go through both primary and secondary select methods and
-    ;; request new newsgroups.
     (while (setq method (gnus-server-get-method nil (pop methods)))
       (setq new-newsgroups nil
 	    gnus-override-subscribe-method method)
@@ -1653,8 +1649,8 @@ gnus-get-unread-articles
 	  (when (setq entry (gnus-group-entry group))
 	    (setcar entry t)))))
 
-    ;; Sort the methods based so that the primary and secondary
-    ;; methods come first.  This is done for legacy reasons to try to
+    ;; Sort the methods based on their ordering in `gnus-select-methods'.
+    ;; This is done for legacy reasons to try to
     ;; ensure that side-effect behavior doesn't change from previous
     ;; Gnus versions.
     (setq type-cache
@@ -1677,11 +1673,9 @@ gnus-get-unread-articles
 	      (setcar elem method))
 	    (push (list method 'ok) methods)))))
 
-    ;; If we have primary/secondary select methods, but no groups from
-    ;; them, we still want to issue a retrieval request from them.
+    ;; For methods with no groups to update, we still request-list if supported.
     (unless dont-connect
-      (dolist (method (cons gnus-select-method
-			    gnus-secondary-select-methods))
+      (dolist (method gnus-select-methods)
 	(when (and (not (assoc method type-cache))
 		   (gnus-check-backend-function 'request-list (car method)))
 	  (with-current-buffer nntp-server-buffer
@@ -1755,14 +1749,13 @@ gnus-method-rank
    ;; Get info for virtual groups last.
    ((eq (car method) 'nnvirtual)
     200)
-   ((eq type 'primary)
-    1)
-   ;; Compute the rank of the secondary methods based on where they
-   ;; are in the secondary select list.
-   ((eq type 'secondary)
-    (let ((i 2))
+   ;; Compute the rank of the method based on where they
+   ;; are in the select list.
+   ((or (eq type 'primary)
+        (eq type 'secondary))
+    (let ((i 1))
       (cl-block nil
-	(cl-dolist (smethod gnus-secondary-select-methods)
+	(cl-dolist (smethod gnus-select-methods)
 	  (when (equal method smethod)
 	    (cl-return i))
 	  (cl-incf i))
@@ -2004,10 +1997,12 @@ gnus-read-active-file
 	   (if (and (not not-native)
 		    (gnus-check-server gnus-select-method))
 	       ;; The native server is available.
-	       (cons gnus-select-method gnus-secondary-select-methods)
+               gnus-select-methods
 	     ;; The native server is down, so we just do the
 	     ;; secondary ones.
-	     gnus-secondary-select-methods)
+             (cl-remove-if
+              (lambda (method) (gnus-method-equal method gnus-select-method))
+              gnus-select-methods))
 	   ;; Also read from the archive server.
 	   (when (gnus-archive-server-wanted-p)
 	     (list "archive")))))
@@ -3067,11 +3062,10 @@ gnus-master-read-slave-newsrc
 ;;;
 
 (defun gnus-read-all-descriptions-files ()
-  (let ((methods (cons gnus-select-method
-		       (nconc
-			(when (gnus-archive-server-wanted-p)
-			  (list "archive"))
-			gnus-secondary-select-methods))))
+  (let ((methods (nconc
+                  (when (gnus-archive-server-wanted-p)
+                    (list "archive"))
+                  gnus-select-methods)))
     (while methods
       (gnus-read-descriptions-file (car methods))
       (setq methods (cdr methods)))
diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el
index 0673ac15f6..490ba51783 100644
--- a/lisp/gnus/gnus.el
+++ b/lisp/gnus/gnus.el
@@ -1032,6 +1032,8 @@ gnus-getenv-nntpserver
 ;;;###autoload(when (fboundp 'custom-autoload)
 ;;;###autoload  (custom-autoload 'gnus-select-method "gnus"))
 
+(defvar gnus-secondary-select-methods)
+(defvar gnus-select-methods)
 (defcustom gnus-select-method
   (list 'nntp (or (gnus-getenv-nntpserver)
                   (when (and gnus-default-nntp-server
@@ -1060,7 +1062,11 @@ gnus-select-method
   :group 'gnus-server
   :group 'gnus-start
   :initialize 'custom-initialize-default
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         (setq gnus-select-methods (cons value gnus-secondary-select-methods)))
   :type 'gnus-select-method)
+(make-obsolete-variable 'gnus-select-method 'gnus-select-methods "27.1" 'set)
 
 (defcustom gnus-message-archive-method "archive"
   "Method used for archiving messages you've sent.
@@ -1136,6 +1142,28 @@ gnus-secondary-select-methods
 
 \(setq gnus-secondary-select-methods \\='((nnml \"\")))"
   :group 'gnus-server
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         (setq gnus-select-methods (cons gnus-select-method value)))
+  :type '(repeat gnus-select-method))
+(make-obsolete-variable 'gnus-secondary-select-methods 'gnus-select-methods "27.1" 'set)
+
+(defcustom gnus-select-methods (cons gnus-select-method gnus-secondary-select-methods)
+  "((BACKEND1 ADDRESS1) (BACKEND2 ADDRESS2) ... ) where BACKEND is a symbol, e.g.,
+nntp, and ADDRESS is a string, e.g., \"flab.flab.edu\".
+
+For example, this specifies a local spool,
+
+\(setq gnus-select-methods `(,(list 'nnspool (system-name))))
+"
+  :group 'gnus-server
+  :initialize 'custom-initialize-default
+  :set (lambda (symbol value)
+         (unless (listp (car value))
+           (setq value (list value)))
+         (set-default symbol value)
+         (setq gnus-select-method (car value))
+         (setq gnus-secondary-select-methods (cdr value)))
   :type '(repeat gnus-select-method))
 
 (defcustom gnus-local-domain nil
diff --git a/lisp/gnus/nnir.el b/lisp/gnus/nnir.el
index 7cb2d1615a..adfb3d6f28 100644
--- a/lisp/gnus/nnir.el
+++ b/lisp/gnus/nnir.el
@@ -44,7 +44,7 @@
 ;; The Lisp setup may involve setting a few variables and setting up the
 ;; search engine. You can define the variables in the server definition
 ;; like this :
-;;   (setq gnus-secondary-select-methods '(
+;;   (setq gnus-select-methods '(
 ;;       (nnimap "" (nnimap-address "localhost")
 ;;                  (nnir-search-engine namazu)
 ;;       )))
diff --git a/lisp/gnus/nnmail.el b/lisp/gnus/nnmail.el
index fc9713e956..4aafa11e4e 100644
--- a/lisp/gnus/nnmail.el
+++ b/lisp/gnus/nnmail.el
@@ -1630,7 +1630,7 @@ nnmail-cache-insert
 	  (insert id "\n"))))))
 
 (defun nnmail-cache-primary-mail-backend ()
-  (let ((be-list (cons gnus-select-method gnus-secondary-select-methods))
+  (let ((be-list gnus-select-methods)
 	(be nil)
 	(res nil)
         (get-new-mail nil))
diff --git a/test/lisp/gnus/gnus-test-select-methods.el b/test/lisp/gnus/gnus-test-select-methods.el
new file mode 100644
index 0000000000..f41e3e7714
--- /dev/null
+++ b/test/lisp/gnus/gnus-test-select-methods.el
@@ -0,0 +1,108 @@
+;;; gnus-test-select-methods.el    -*- lexical-binding:t -*-
+
+;; Copyright (C) 2019 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'gnus)
+(require 'gnus-int)
+(require 'gnus-start)
+
+(eval-when-compile
+  (put 'gnus-secondary-select-methods 'byte-obsolete-variable nil)
+  (put 'gnus-select-method 'byte-obsolete-variable nil)
+  (put 'gnus-nntp-server 'byte-obsolete-variable nil))
+
+(ert-deftest gnus-test-select-methods-basic ()
+  "Customizing `gnus-select-method' and `gnus-secondary-select-methods'
+also modifies `gnus-select-methods'."
+  (let (gnus-select-method
+        gnus-secondary-select-methods
+        gnus-select-methods
+        (test-methods '((nnnil) (nntp "flab.flab.edu"))))
+    (custom-set-variables `(gnus-select-method (quote ,(car test-methods)))
+                          `(gnus-secondary-select-methods (quote ,(cdr test-methods))))
+    (should (cl-every #'identity
+                      (cl-mapcar #'gnus-methods-equal-p gnus-select-methods test-methods)))
+    (should (gnus-method-equal gnus-select-method (car gnus-select-methods)))
+    (should (cl-every #'identity
+                      (cl-mapcar #'gnus-methods-equal-p gnus-secondary-select-methods
+                                 (cdr gnus-select-methods))))))
+
+(ert-deftest gnus-test-select-methods-override ()
+  "Customizing `gnus-select-methods' overrides earlier customizations
+of `gnus-select-method' and `gnus-secondary-select-methods'."
+  (let (gnus-select-method
+        gnus-secondary-select-methods
+        gnus-select-methods
+        (test-methods '((nnnil) (nntp "flab.flab.edu")))
+        (override-methods '((nntp "override") (nnnil))))
+    (custom-set-variables `(gnus-select-method (quote ,(car test-methods)))
+                          `(gnus-secondary-select-methods (quote ,(cdr test-methods)))
+                          `(gnus-select-methods (quote ,override-methods)))
+    (should (cl-every #'identity
+                      (cl-mapcar #'gnus-methods-equal-p gnus-select-methods override-methods)))
+    (should (gnus-method-equal gnus-select-method (car gnus-select-methods)))
+    (should (cl-every #'identity
+                      (cl-mapcar #'gnus-methods-equal-p gnus-secondary-select-methods
+                                 (cdr gnus-select-methods))))))
+
+(ert-deftest gnus-test-gnus-start-news-server ()
+  "Test an archaic method of initiating gnus."
+  (let (gnus-current-select-method
+        (gnus-nntp-server "::"))
+    (cl-letf (((symbol-function 'gnus-y-or-n-p) #'ignore))
+      (gnus-start-news-server)
+      (should (gnus-method-equal gnus-select-method `(nnspool ,(system-name)))))))
+
+(ert-deftest gnus-test-gnus-method-rank ()
+  "Ensure unification does right by `gnus-method-rank'."
+  (let (gnus-select-method
+        gnus-secondary-select-methods
+        gnus-select-methods
+        type-cache
+        (test-methods '((nnnil) (nntp "flab.flab.edu")))
+        (sort-f (lambda (c1 c2)
+                  (< (gnus-method-rank (cadr c1) (car c1))
+                     (gnus-method-rank (cadr c2) (car c2))))))
+    (custom-set-variables `(gnus-select-methods (quote ,test-methods)))
+    (dolist (method test-methods)
+      (push `(,method
+              ,(cond
+                ((gnus-secondary-method-p method) 'secondary)
+                ((gnus-method-equal gnus-select-method method) 'primary)
+                (t 'foreign)))
+            type-cache))
+    (equal '(nnnil nntp)
+           (mapcar (lambda (x) (car (car x))) (sort type-cache sort-f)))))
+
+(ert-deftest gnus-test-gnus-read-active-file ()
+  "Ensure unification does right by `gnus-read-active-file'."
+  (let (gnus-select-method
+        gnus-secondary-select-methods
+        gnus-select-methods
+        (test-methods '((nnnil) (nntp "flab.flab.edu"))))
+    (custom-set-variables `(gnus-select-methods (quote ,test-methods)))
+    (should (equal
+             (cl-remove-if (lambda (method)
+                             (gnus-method-equal method gnus-select-method))
+                           gnus-select-methods)
+             gnus-secondary-select-methods))))
+
+;;; gnus-test-select-methods.el ends here
-- 
2.23.0