Skip to content

Commit 5737a49

Browse files
committed
update to latest configure
1 parent a05665b commit 5737a49

File tree

10 files changed

+365
-398
lines changed

10 files changed

+365
-398
lines changed

RcppParallel.Rproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ RnwWeave: Sweave
1313
LaTeX: pdfLaTeX
1414

1515
BuildType: Package
16-
PackageInstallArgs: --with-keep.source
16+
PackageInstallArgs: --with-keep.source --clean
1717
PackageCheckArgs: --as-cran

cleanup

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/usr/bin/env sh
22
: ${R_HOME=`R RHOME`}
3-
"${R_HOME}/bin/R" --vanilla --slave -f tools/config/cleanup.R
3+
"${R_HOME}/bin/Rscript" tools/config.R cleanup

cleanup.win

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#!/usr/bin/env sh
2-
"${R_HOME}/bin${R_ARCH_BIN}/R.exe" --vanilla --slave -f tools/config/cleanup.R
2+
"${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" tools/config.R cleanup

configure

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/usr/bin/env sh
22
: ${R_HOME=`R RHOME`}
3-
"${R_HOME}/bin/R" --vanilla --slave -f tools/config/configure.R
3+
"${R_HOME}/bin/Rscript" tools/config.R configure

configure.win

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#!/usr/bin/env sh
2-
"${R_HOME}/bin${R_ARCH_BIN}/R.exe" --vanilla --slave -f tools/config/configure.R
2+
"${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" tools/config.R configure

tools/config.R

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
# configure-database.R ----
2+
3+
#' Retrieve the Global Configuration Database
4+
#'
5+
#' Retrieve the global configuration database (as an \R environment).
6+
#'
7+
#' @family configure-db
8+
#'
9+
#' @export
10+
configure_database <- local({
11+
database <- new.env(parent = emptyenv())
12+
function() database
13+
})
14+
15+
#' Define Variables for the Configuration Database
16+
#'
17+
#' Define variables to be used as part of the default configuration database.
18+
#' These will be used by [configure_file()] when no configuration database
19+
#' is explicitly supplied.
20+
#'
21+
#' @param ... A set of named arguments, mapping configuration names to values.
22+
#'
23+
#' @family configure-db
24+
#'
25+
#' @export
26+
configure_define <- function(...) {
27+
envir <- configure_database()
28+
list2env(list(...), envir = envir)
29+
}
30+
31+
#' @export
32+
define <- configure_define
33+
34+
35+
# utils.R ----
36+
37+
#' Configure a File
38+
#'
39+
#' Configure a file, replacing any instances of `@`-delimited variables, e.g.
40+
#' `@VAR@`, with the value of the variable called `VAR` in the associated
41+
#' `config` environment.
42+
#'
43+
#' @param source The file to be configured.
44+
#' @param target The file to be generated.
45+
#' @param config The configuration database.
46+
#' @param verbose Boolean; report files as they are configured?
47+
#'
48+
#' @family configure
49+
#'
50+
#' @export
51+
configure_file <- function(
52+
source,
53+
target = sub("[.]in$", "", source),
54+
config = configure_database(),
55+
verbose = configure_verbose())
56+
{
57+
contents <- readLines(source, warn = FALSE)
58+
enumerate(config, function(key, val) {
59+
needle <- paste("@", key, "@", sep = "")
60+
replacement <- val
61+
contents <<- gsub(needle, replacement, contents)
62+
})
63+
64+
ensure_directory(dirname(target))
65+
writeLines(contents, con = target)
66+
67+
info <- file.info(source)
68+
Sys.chmod(target, mode = info$mode)
69+
70+
if (isTRUE(verbose)) {
71+
fmt <- "** configured file: '%s' => '%s'"
72+
message(sprintf(fmt, source, target))
73+
}
74+
}
75+
76+
#' Configure Files in a Directory
77+
#'
78+
#' This companion function to [configure_file()] can be used to
79+
#' configure all `.in` files within a directory.
80+
#'
81+
#' @param path The path to a directory in which files should be configured.
82+
#' @param config The configuration database to be used.
83+
#' @param verbose Boolean; report files as they are configured?
84+
#'
85+
#' @family configure
86+
#'
87+
#' @export
88+
configure_directory <- function(
89+
path = ".",
90+
config = configure_database(),
91+
verbose = configure_verbose())
92+
{
93+
files <- list.files(
94+
path = path,
95+
pattern = "[.]in$",
96+
full.names = TRUE)
97+
98+
lapply(files, configure_file, config = config, verbose = verbose)
99+
}
100+
101+
configure_auto <- function(type) {
102+
configure_common(type = type)
103+
}
104+
105+
configure_common <- function(type) {
106+
107+
if (!isTRUE(getOption("configure.common", default = TRUE)))
108+
return(invisible(FALSE))
109+
110+
sources <- list.files(
111+
path = c("R", "src"),
112+
pattern = "[.]in$",
113+
full.names = TRUE
114+
)
115+
116+
sources <- sub("[.]/", "", sources)
117+
118+
if (type == "configure") {
119+
lapply(sources, configure_file)
120+
} else if (type == "cleanup") {
121+
targets <- sub("[.]in$", "", sources)
122+
lapply(targets, remove_file)
123+
}
124+
125+
invisible(TRUE)
126+
}
127+
128+
#' Read R Configuration for a Package
129+
#'
130+
#' Read the \R configuration, as through `R CMD config`.
131+
#'
132+
#' @param ... The \R configuration values to read (as a character vector).
133+
#' If empty, all values are read as through `R CMD config --all`).
134+
#' @param package The path to the \R package's sources.
135+
#' @param envir The environment in which the configuration information should
136+
#' be assigned. By default, the [configure_database()] is populated with the
137+
#' requested values.
138+
#' @param verbose Boolean; notify the user as \R configuration is read?
139+
#'
140+
#' @export
141+
read_r_config <- function(
142+
...,
143+
package = Sys.getenv("R_PACKAGE_DIR", unset = "."),
144+
envir = configure_database(),
145+
verbose = configure_verbose())
146+
{
147+
# move to requested directory
148+
owd <- setwd(package)
149+
on.exit(setwd(owd), add = TRUE)
150+
R <- file.path(R.home("bin"), "R")
151+
152+
values <- unlist(list(...), recursive = TRUE)
153+
if (length(values) == 0) {
154+
if (verbose)
155+
message("** executing 'R CMD config --all'")
156+
output <- system2(R, c("CMD", "config", "--all"), stdout = TRUE)
157+
equalsIndex <- regexpr("=", output, fixed = TRUE)
158+
keys <- trim_whitespace(substring(output, 1, equalsIndex - 1))
159+
config <- as.list(trim_whitespace(substring(output, equalsIndex + 1)))
160+
names(config) <- keys
161+
162+
} else {
163+
if (verbose)
164+
message("** executing 'R CMD config'")
165+
config <- lapply(values, function(value) {
166+
system2(R, c("CMD", "config", value), stdout = TRUE)
167+
})
168+
names(config) <- values
169+
}
170+
171+
list2env(config, envir = envir)
172+
}
173+
174+
#' Concatenate the Contents of a Set of Files
175+
#'
176+
#' Given a set of files, concatenate their contents into
177+
#' a single file.
178+
#'
179+
#' @param sources An \R list of files
180+
#' @param target The file to use for generation.
181+
#' @param headers Headers to be used for each file copied.
182+
#' @param preamble Text to be included at the beginning of the document.
183+
#' @param postamble Text to be included at the end of the document.
184+
#' @param verbose Boolean; inform the user when the requested file is created?
185+
#'
186+
#' @export
187+
concatenate_files <- function(
188+
sources,
189+
target,
190+
headers = sprintf("# %s ----", basename(sources)),
191+
preamble = NULL,
192+
postamble = NULL,
193+
verbose = configure_verbose())
194+
{
195+
pieces <- vapply(seq_along(sources), function(i) {
196+
source <- sources[[i]]
197+
header <- headers[[i]]
198+
contents <- trim_whitespace(read_file(source))
199+
paste(header, contents, "", sep = "\n\n")
200+
}, character(1))
201+
202+
all <- c(preamble, pieces, postamble)
203+
204+
ensure_directory(dirname(target))
205+
writeLines(all, con = target)
206+
207+
if (verbose) {
208+
fmt <- "** created file '%s'"
209+
message(sprintf(fmt, target))
210+
}
211+
212+
TRUE
213+
}
214+
215+
#' Add Configure Infrastructure to an R Package
216+
#'
217+
#' Add the infrastructure needed to configure an R package.
218+
#'
219+
#' @param package The path to the top-level directory of an \R package.
220+
#' @export
221+
use_configure <- function(package = ".") {
222+
223+
# preserve working directory
224+
owd <- getwd()
225+
on.exit(setwd(owd), add = TRUE)
226+
227+
# find resources
228+
package <- normalizePath(package, winslash = "/")
229+
resources <- system.file("resources", package = "configure")
230+
231+
# copy into temporary directory
232+
dir <- tempfile("configure-")
233+
on.exit(unlink(dir, recursive = TRUE), add = TRUE)
234+
235+
dir.create(dir)
236+
file.copy(resources, dir, recursive = TRUE)
237+
238+
# rename resources directory
239+
setwd(dir)
240+
file.rename(basename(resources), basename(package))
241+
242+
# now, copy these files back into the target directory
243+
file.copy(basename(package), dirname(package), recursive = TRUE)
244+
245+
# ensure DESCRIPTION contains 'Biarch: TRUE' for Windows
246+
setwd(package)
247+
DESCRIPTION <- read_file("DESCRIPTION")
248+
if (!grepl("(?:^|\n)Biarch:", DESCRIPTION)) {
249+
DESCRIPTION <- paste(DESCRIPTION, "Biarch: TRUE", sep = "\n")
250+
DESCRIPTION <- gsub("\n{2,}", "\n", DESCRIPTION)
251+
cat(DESCRIPTION, file = "DESCRIPTION", sep = "\n")
252+
}
253+
}
254+
255+
ensure_directory <- function(dir) {
256+
info <- file.info(dir)
257+
258+
# no file exists at this location; try to make it
259+
if (is.na(info$isdir)) {
260+
dir.create(info$isdir, recursive = TRUE, showWarnings = FALSE)
261+
if (!file.exists(dir))
262+
stop("failed to create directory '", dir, "'")
263+
return(TRUE)
264+
}
265+
266+
# a directory already exists
267+
if (isTRUE(info$isdir))
268+
return(TRUE)
269+
270+
# a file exists, but it's not a directory
271+
stop("file already exists at path '", dir, "'")
272+
}
273+
274+
enumerate <- function(x, f, ...) {
275+
nms <- if (is.environment(x)) ls(envir = x) else names(x)
276+
lapply(nms, function(nm) {
277+
f(nm, x[[nm]], ...)
278+
})
279+
}
280+
281+
read_file <- function(path) {
282+
paste(readLines(path, warn = FALSE), collapse = "\n")
283+
}
284+
285+
remove_file <- function(
286+
path,
287+
verbose = configure_verbose())
288+
{
289+
info <- file.info(path)
290+
if (!is.na(info$isdir)) {
291+
unlink(path, recursive = isTRUE(info$isdir))
292+
if (verbose) {
293+
fmt <- "** removed file '%s'"
294+
message(sprintf(fmt, path))
295+
}
296+
}
297+
298+
TRUE
299+
}
300+
301+
source_file <- function(
302+
path,
303+
envir = parent.frame())
304+
{
305+
contents <- read_file(path)
306+
invisible(eval(parse(text = contents), envir = envir))
307+
}
308+
309+
trim_whitespace <- function(x) {
310+
gsub("^[[:space:]]*|[[:space:]]*$", "", x)
311+
}
312+
313+
configure_verbose <- function() {
314+
getOption("configure.verbose", !interactive())
315+
}
316+
317+
318+
# run.R ----
319+
320+
local({
321+
322+
# extract path to install script
323+
args <- commandArgs(TRUE)
324+
type <- args[[1]]
325+
326+
# report start of execution
327+
package <- Sys.getenv("R_PACKAGE_NAME", unset = "<unknown>")
328+
fmt <- "* preparing to %s package '%s' ..."
329+
message(sprintf(fmt, type, package))
330+
331+
# execute the requested script
332+
path <- sprintf("tools/config/%s.R", type)
333+
if (file.exists(path)) source_file(path)
334+
335+
# perform automatic configuration
336+
configure_auto(type = type)
337+
338+
# report end of execution
339+
fmt <- "* finished %s for package '%s'"
340+
message(sprintf(fmt, type, package))
341+
})
342+
343+

0 commit comments

Comments
 (0)