4 min read

debugging with docker and r-devel

If you’ve not heard, there’s a big move away from Travis to GitHub Actions for continuous testing of R packages. I’m so glad for the infrastructure to help, but it’s a bit of work to figure it out.

But that’s not what I’m talking about today. Today I want to talk about using docker to debug an R package that is throwing an error in the development version of R. This came up because with the new GitHub Actions infrastructure, I can now test my R packages on multiple OSs and with multiple versions of R, and today R/qtl was shown to throw an error in R-devel.

If you look at the test history, you’ll see I was mostly screwing around trying to get LaTeX installed and then trying to get all of the needed LaTeX packages for a 10-year-old Sweave-based vignette. And I got through that only to find that there was a different actual R problem that needed to be fixed.

Not wanting to install the development version of R on my machine, I pondered cloud installations, and then thought, “Hmm, this seems like a good application for docker. I just need to find a docker container with R-devel, install R/qtl, and then try it out.” And well, it was pretty simple.

  1. Install Docker. See the official instructions. I’m working on a Ubuntu laptop, so I did:

    sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
    sudo apt update
    sudo apt install docker-ce docker-ce-cli containerd.io
    
  2. Create a Dockerfile which builds off rocker/r-devel and installs the package to be tested. (In this rocker image, R is the current version of R and RD is the devel version, so we need to use RD to install the package.)

    FROM rocker/r-devel
    RUN RD -e "install.packages('qtl')"
    

    You might want to install some further tools like git, and some further packages like devtools and testthat. The latter may require yet further tools like libuv1-dev and libxml2-dev, and to make it easier, you might want use the rocker/tidyverse:devel, as in the following example:

    FROM rocker/tidyverse:devel
    RUN apt install -y git
    RUN R -e "install.packages(c('broman', 'qtl', 'qtl2'))
    

    But that docker image seems to be updated less often, so maybe stick to rocker/r-devel as follows. (But this didn’t totally work for me; to install devtools I seem to need libxml2-dev but I wasn’t able to get it to work.)

    FROM rocker/r-devel
    RUN apt install -y git libuv1-dev
    RUN R -e "install.packages(c('testthat', 'devtools', 'broman', 'qtl', 'qtl2'))"
    

    Here’s the error I got:

    Error: Unable to satisfy dependencies. Reached two conflicting decisions:
       1. libxml2-16:amd64=2.15.2+dfsg-0.1 is not selected for install
       2. libxml2-16:amd64=2.15.2+dfsg-0.1 is selected as a downgrade because:
          1. libxml2-dev:amd64=2.15.2+dfsg-0.1 is selected for install
          2. libxml2-dev:amd64=2.15.2+dfsg-0.1 Depends libxml2-16 (= 2.15.2+dfsg-0.1)
    

    And here’s what worked:

    FROM rocker/r-devel
    RUN apt update && apt upgrade -y
    RUN apt install -y --allow-downgrades git libuv1-dev libxml2-dev libxml2-16:amd64=2.15.2+dfsg-0.1
    RUN R -e "install.packages(c('devtools', 'testthat', 'broman', 'qtl', 'qtl2'))"
    
  3. Build the docker image.

    docker build -t rdevel-qtl .
    
  4. Fire up that image in a container.

    docker run -it rdevel-qtl bash
    
  5. Run R and load the package.

    The above puts you into a bash shell within the container. If you used rocker/r-devel, type RD to fire up the devel version of R. (If you used rocker/tidyverse:devel, just type R.) Then load your package and mess about. I quickly saw where I went wrong.

  6. Fix the problem and test it.

    I should add a formal test of this bug, and I should also look for all other possible instances of this problem. (I blanche to think of them.)

    But for now I just plunged in and fixed it, pushed the change to GitHub, and then tested it out in my container by installing the repaired version with the remotes package.

    install.packages("remotes")
    remotes::install_github("kbroman/qtl")
    

There’s a lot more that one can do with Docker, but this was a pretty quick and satisfying experience poking around in the development version of R to fix a bug in my ancient and creaky package.

I gave a talk about docker in my Advanced Data Analysis course last spring. You can look at the slides, including a version with notes of what I said, and watch the lecture. (It’s recommended that you do so on fast-forward.) The course resources page points to other resources on docker.