From henrik.bengtsson at ucsf.edu  Mon May 18 02:13:15 2015
From: henrik.bengtsson at ucsf.edu (Henrik Bengtsson)
Date: Sun, 17 May 2015 17:13:15 -0700
Subject: [Rd] install.packages() / update.packages() sometimes outputs to
 stdout and sometimes to stderr [and menu() & readline()]
Message-ID: <CAFDcVCTBW7NTa7YkK+avA9g0TA=kV2oOvVbH6YVMTOE7PukVjQ@mail.gmail.com>

I've noticed that install.packages()
[https://svn.r-project.org/R/trunk/src/library/utils/R/packages.R] and
update.packages()
[https://svn.r-project.org/R/trunk/src/library/utils/R/packages2.R]
sometimes output to stdout and sometimes to stderr.

It looks like stderr is used (e.g. via cat()) when the message is part
of querying the user, e.g.

update.packages <- function(lib.loc = NULL, repos = getOption("repos"),
[...]
            cat(old[k, "Package"], ":\n",
                "Version", old[k, "Installed"],
                "installed in", old[k, "LibPath"],
                if(checkBuilt) paste("built under R", old[k, "Built"]),
                "\n",
                "Version", old[k, "ReposVer"], "available at",
                simplifyRepos(old[k, "Repository"], type))
            cat("\n")
            answer <- substr(readline("Update (y/N/c)?  "), 1L, 1L)
            if(answer == "c" | answer == "C") {
                cat("cancelled by user\n")
                return(invisible())
            }

but it is not consistently so, because some are sent to stderr (e.g.
via message()), e.g.

install.packages <-
    function(pkgs, lib, repos = getOption("repos"),
[...]
                if(action == "interactive" && interactive()) {
                    msg <-
                        ngettext(sum(later & hasSrc),
                                 "Do you want to install from sources
the package which needs compilation?",
                                 "Do you want to install from sources
the packages which need compilation?")
                    message(msg, domain = NA)
                    res <- readline("y/n: ")
                    if(res != "y") later <- later & !hasSrc
                } else if (action == "never") {
                    cat("  Binaries will be installed\n")
                    later <- later & !hasSrc
                }

Also, as one see in the latter example, it is not only interactive
user queries for which stdout is used.  It's simply not consistent -
at least I cannot see pattern.

If these are not intended behaviors, I'm happy to provide patches.
I'd prefer stderr for all user queries (see below) - but I can also
see how this is something that needs considered thoughts and made an
official design policy across the R base distribution.


[Related to the above but could deserve it's own thread (feel free to
move the below to its own thread)]

utils::menu(..., graphics=FALSE)
[https://svn.r-project.org/R/trunk/src/library/utils/R/menu.R] queries
the user via standard output, which becomes an issue when running
interactive report generators, which mostly captures stdout and makes
it part of the produced artifact.  Personally, I'd argue that querying
the user via stderr would be a better choice in more cases.

Also, it's a bit weird that base::readline(), which is used for the
actual prompting of the user, is sent neither to R's stdout nor
stderr, e.g.

> zz <- file("all.Rout", open = "wt")
> sink(zz); sink(zz, type = "message")
> ans <- menu(letters[1:3], title="Select one:", graphics=FALSE)
Selection: 1

> sink(type = "message"); sink()
> ans
[1] 1

> cat(readLines("all.Rout"), sep="\n")
Select one:

1: a
2: b
3: c

Note the only thing displayed to the user is the prompt "Selection: ",
which is generated by readline().  It does however output to the
system's stdout (verified on Linux and Windows), e.g.

$ Rscript -e "readline('Press ENTER: ')" > stdout.log
$ cat stdout.log
Press ENTER:
[1] ""

Compare this to how it works in, for instance, bash:

$ read -p "Press ENTER: " ans > stdout.log
Press ENTER:
$ read -p "Press ENTER: " ans > stderr.log
$ cat stderr.log
Press ENTER:

My preference would be that menu() and readline() and other messages
for querying the user would output to the same connection/stream.
Again, I'd favor stderr over stdout, but possibly even a third
alternative designed specifically for user queries, cf. my R-devel
post '[Rd] Output to "raw console" rather than stdout/stderr?' on
2015-02-01 (https://stat.ethz.ch/pipermail/r-devel/2015-February/070578.html).
Just like when using menu(..., graphics=TRUE), this would not clutter
up the output to stdout (or stderr).  But even without this third
alternative, I argue that stderr is better than stdout. I'm happy to
provide patches for this as well.


Thanks,

Henrik



[Rd] install.packages() / update.packages() sometimes outputs to stdout and sometimes to stderr [and menu() & readline()]
Henrik Bengtsson