summaryrefslogtreecommitdiff
path: root/R/guix.install.R
blob: 66bb340c12a8dcf052320bbca240361a540264d2 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
## Copyright (C) 2020-2022 Ricardo Wurmus
##
## This program 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.
##
## This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

## TODO:
## - allow installation of more than one package

guix.install <- function (package, profile = NULL, guix = "guix", archive = NULL)
{
    if (is.null (profile)) {
        ## Use the default profile unless otherwise specified.
        guix_profile <- Sys.getenv ("GUIX_PROFILE", unset = NA)
        if (is.na (guix_profile)) {
            profile <- paste (Sys.getenv ("HOME"), ".guix-profile", sep = "/")
        } else {
            profile <- guix_profile
        }
    } else {
        ## Create the parent directory if necessary.
        parent <- dirname (profile)
        if (! dir.exists (parent)) {
            dir.create (parent, recursive = TRUE)
        }
    }

    ## Location of on-the-fly generated packages
    scratch <- paste (Sys.getenv ("HOME"), ".Rguix", "packages.scm", sep = "/")

    ## split package path, put scratch location first
    package_path <- NULL
    old_package_path <- Sys.getenv ("GUIX_PACKAGE_PATH")
    entries <- strsplit (old_package_path, ":")[[1]]
    package_path <- paste (unique (c(dirname (scratch), entries)), sep = ":")
    Sys.setenv (GUIX_PACKAGE_PATH=package_path)

    is_url <- length (grep ("^https?://", package)) > 0

    if (!is_url) {
        ## The normalized name used by Guix packages
        guix_name <- paste0 ("r-", gsub ("[^a-z0-9]", "-", tolower (package)))

        ## Does the package already exist?
        error <- system2 (guix, c("show", guix_name),
                          stdout = NULL, stderr = NULL)
    }
    
    ## Attempt to import the package
    if (is_url || (error > 0)) {
        ## Build a scratch module
        if (! dir.exists (dirname (scratch))) {
            dir.create (dirname (scratch), recursive = TRUE)
        }
        if (! file.exists (scratch)) {
            cat ("
(define-module (packages)
  #:use-module (gnu)
  #:use-module (guix)
  #:use-module (guix git-download)
  #:use-module (guix hg-download)
  #:use-module (guix build-system r)
  #:use-module (guix licenses))
", file = scratch)
        }

        if (is.null (archive)) {
            archive <- if (is_url) {
                           "git" # TODO: what about hg?
                       } else {
                           ## The importer will retry importing from CRAN if a
                           ## package is not found on Bioconductor.
                           "bioconductor"
                       }
        }

        definitions <- suppressWarnings (system2 (guix, c("import", "cran",
                                                          "--recursive",
                                                          "--style=specification",
                                                          paste ("--archive", archive, sep = "="),
                                                          package),
                                                  stdout = TRUE))

        ## Abort on error
        status <- attr (definitions, "status")
        if (!is.null (status) && (status > 0)) {
            stop (paste("Failed to import", package))
        }

        ## Get guix_name from definitions
        pattern <- "\\(name \"([^\"]+)\"\\)"
        name <- grep (pattern, definitions, value = TRUE)
        guix_name <- sub (pattern, "\\1", name)

        ## Store generated package definitions.
        cat (";; Imported from within R at ", date(), "\n",
             file = scratch, append = TRUE)
        cat (definitions, sep = "\n",
             file = scratch, append = TRUE)
    }

    ## Install the package.
    error <- system2 (guix, c("package", paste ("--profile", profile, sep = "="),
                              "--install", guix_name))

    ## Extend the R load path.
    if (error == 0) {
        .libPaths (paste (profile, "site-library", sep = "/"))
    }
}