blob: 765b1ed4a6874cd2cf2d6782079e01a8485a026f [file] [log] [blame]
# File src/library/utils/R/indices.R
# Part of the R package, https://www.R-project.org
#
# Copyright (C) 1995-2017 The R Core Team
#
# 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 2 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.
#
# A copy of the GNU General Public License is available at
# https://www.R-project.org/Licenses/
packageDescription <-
function(pkg, lib.loc = NULL, fields = NULL, drop = TRUE, encoding = "")
{
retval <- list()
if(!is.null(fields)){
fields <- as.character(fields)
retval[fields] <- NA
}
## If the NULL default for lib.loc is used,
## the loaded packages/namespaces are searched before the libraries.
pkgpath <-
if(is.null(lib.loc)) {
if(pkg == "base")
file.path(.Library, "base")
else if(isNamespaceLoaded(pkg))
getNamespaceInfo(pkg, "path")
else if((envname <- paste0("package:", pkg)) %in% search()) {
attr(as.environment(envname), "path")
## could be NULL if a perverse user has been naming
## environments to look like packages.
}
}
if(is.null(pkgpath)) pkgpath <- ""
if(pkgpath == "") {
libs <- if(is.null(lib.loc)) .libPaths() else lib.loc
for(lib in libs)
if(file.access(file.path(lib, pkg), 5) == 0L) {
pkgpath <- file.path(lib, pkg)
break
}
}
if(pkgpath == "") {
warning(gettextf("no package '%s' was found", pkg), domain = NA)
return(NA)
}
## New in 2.7.0: look for installed metadata first.
## We always need to be able to drop back to the file as this
## is used during package installation.
if(file.exists(file <- file.path(pkgpath, "Meta", "package.rds"))) {
desc <- readRDS(file)$DESCRIPTION
if(length(desc) < 1)
stop(gettextf("metadata of package '%s' is corrupt", pkg),
domain = NA)
desc <- as.list(desc)
} else if(file.exists(file <- file.path(pkgpath,"DESCRIPTION"))) {
dcf <- read.dcf(file=file)
if(NROW(dcf) < 1L)
stop(gettextf("DESCRIPTION file of package '%s' is corrupt", pkg),
domain = NA)
desc <- as.list(dcf[1,])
} else file <- ""
if(nzchar(file)) {
## read the Encoding field if any
enc <- desc[["Encoding"]]
if(!is.null(enc) && !is.na(encoding)) {
## Determine encoding and re-encode if necessary and possible.
if (missing(encoding) && Sys.getlocale("LC_CTYPE") == "C")
encoding <- "ASCII//TRANSLIT"
if(encoding != enc) { # try to translate from 'enc' to 'encoding' --------
## might have an invalid encoding ...
newdesc <- try(lapply(desc, iconv, from = enc, to = encoding))
dOk <- function(nd) !inherits(nd, "error") && !anyNA(nd)
ok <- dOk(newdesc)
if(!ok) # try again
ok <- dOk(newdesc <- try(lapply(desc, iconv, from = enc,
to = paste0(encoding,"//TRANSLIT"))))
if(!ok) # try again
ok <- dOk(newdesc <- try(lapply(desc, iconv, from = enc,
to = "ASCII//TRANSLIT", sub = "?")))
if(ok)
desc <- newdesc
else
warning("'DESCRIPTION' file has an 'Encoding' field and re-encoding is not possible", call. = FALSE)
}
}
if(!is.null(fields)){
ok <- names(desc) %in% fields
retval[names(desc)[ok]] <- desc[ok]
}
else
retval[names(desc)] <- desc
}
if((file == "") || (length(retval) == 0)){
warning(gettextf("DESCRIPTION file of package '%s' is missing or broken", pkg), domain = NA)
return(NA)
}
if(drop & length(fields) == 1L)
return(retval[[1L]])
class(retval) <- "packageDescription"
if(!is.null(fields)) attr(retval, "fields") <- fields
attr(retval, "file") <- file
retval
}
print.packageDescription <-
function(x, abbrCollate = 0.8 * getOption("width"), ...)
{
xx <- x
xx[] <- lapply(xx, function(x) if(is.na(x)) "NA" else x)
if(abbrCollate > 0 && any(names(xx) == "Collate")) {
## trim a long "Collate" field -- respecting word boundaries
wrds <- strsplit(xx$Collate,"[ \n]")[[1L]]
k <- which.max(cumsum(nchar(wrds)) > abbrCollate) - 1L
xx$Collate <- paste(c(wrds[seq_len(k)], "....."), collapse=" ")
}
write.dcf(as.data.frame.list(xx, optional = TRUE))
cat("\n-- File:", attr(x, "file"), "\n")
if(!is.null(attr(x, "fields"))){
cat("-- Fields read: ")
cat(attr(x, "fields"), sep = ", ")
cat("\n")
}
invisible(x)
}
# Simple convenience functions
maintainer <- function(pkg)
{
force(pkg)
desc <- packageDescription(pkg)
if(is.list(desc)) gsub("\n", " ", desc$Maintainer, fixed = TRUE)
else NA_character_
}
packageVersion <- function(pkg, lib.loc = NULL)
{
res <- suppressWarnings(packageDescription(pkg, lib.loc=lib.loc,
fields = "Version"))
if (!is.na(res)) package_version(res) else
stop(packageNotFoundError(pkg, lib.loc, sys.call()))
}
##' Auxiliary: generalize extraction from "Built"
asDateBuilt <- function(built) {
as.Date(strsplit(built, split="; ", fixed=TRUE)[[1L]][[3L]],
format = "%Y-%m-%d")
}
packageDate <- function(pkg, lib.loc = NULL,
date.fields = c("Date", "Packaged", "Date/Publication", "Built"),
tryFormats = c("%Y-%m-%d", "%Y/%m/%d", "%D", "%m/%d/%y"),
desc = packageDescription(pkg, lib.loc=lib.loc, fields=date.fields))
{
useDesc <- is.list(desc) && length(names(desc)) >= 1
for (fld in date.fields) {
res <- if(useDesc) {
r <- desc[[fld]]
if(is.null(r)) NA_character_ else r
} else
packageDescription(pkg, lib.loc=lib.loc, fields = fld)
res <- if(fld == "Built" && !is.na(res))
tryCatch(asDateBuilt(res),
error = function(e) {
warning("Invalid \"Built\": ", conditionMessage(e))
NA_character_
})
else as.Date(res, tryFormats=tryFormats,
optional = TRUE)# NA instead of errror
if (!is.na(res))
break
}
if(is.na(res)) res else structure(res, field = fld) # NA or 'Date' object
}
## used with firstOnly = TRUE for example()
## used with firstOnly = FALSE in help()
index.search <- function(topic, paths, firstOnly = FALSE)
{
res <- character()
for (p in paths) {
if(file.exists(f <- file.path(p, "help", "aliases.rds")))
al <- readRDS(f)
else if(file.exists(f <- file.path(p, "help", "AnIndex"))) {
## aliases.rds was introduced before 2.10.0, as can phase this out
foo <- scan(f, what = list(a="", b=""), sep = "\t", quote = "",
na.strings = "", quiet = TRUE)
al <- structure(foo$b, names = foo$a)
} else next
f <- al[topic]
if(is.na(f)) next
res <- c(res, file.path(p, "help", f))
if(firstOnly) break
}
res
}
print.packageIQR <- function(x, ...)
{
db <- x$results
## Split according to Package.
out <- if(nrow(db) > 0L)
lapply(split(seq_len(nrow(db)), db[, "Package"]),
function(ind) db[ind, c("Item", "Title"), drop = FALSE])
outFile <- tempfile("RpackageIQR")
outConn <- file(outFile, open = "w")
first <- TRUE
for(pkg in names(out)) {
writeLines(paste0(ifelse(first, "", "\n"), x$title,
" in package ", sQuote(pkg), ":\n"),
outConn)
writeLines(formatDL(out[[pkg]][, "Item"],
out[[pkg]][, "Title"]),
outConn)
first <- FALSE
}
if(first) {
close(outConn)
unlink(outFile)
writeLines(paste("no", tolower(x$title), "found"))
if(!is.null(x$footer))
writeLines(c("", x$footer))
}
else {
if(!is.null(x$footer))
writeLines(c("\n", x$footer), outConn)
close(outConn)
file.show(outFile, delete.file = TRUE,
title = paste("R", tolower(x$title)))
}
invisible(x)
}