diff --git a/.Rbuildignore b/.Rbuildignore index 85c65e0..e71ee30 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,4 +1,4 @@ -^.*\.Rproj$ +^rprojroot\.Rproj$ ^\.Rproj\.user$ ^\.gitignore$ ^README\.md$ @@ -20,3 +20,5 @@ ^_pkgdown\.yml$ ^revdep$ ^tic\.R$ +^tests/testthat/hierarchy/a/b/\.projectile$ +^API$ diff --git a/.deploy_key.enc b/.deploy_key.enc deleted file mode 100644 index ea9c210..0000000 Binary files a/.deploy_key.enc and /dev/null differ diff --git a/.deploy_key.pub b/.deploy_key.pub deleted file mode 100644 index c86dcbb..0000000 --- a/.deploy_key.pub +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3qkRRQ4XiAiDvxyIj6V1 -d2RuaFicbrjiGBQ4ZzbqbhuX6lzejvy2XdaOV/6lZiNHg0wmGpO2qtZI4rAdglx+ -RAqOzK2UihtFGxQsCU7YI1J7ei0Vz1rsjq1Tz0J5+IcuTl2bWLihE2O+jufH/+Fm -EUjezx/gx0dv3ycpkCWjWgqIy9Jv62dRtKdu0BAw5F26/ELOwMvC210La2Q40Q2x -6uvFHWET4T2EsqZaT4srnEpeVPBiZSKFtliRFZCU8wk76avDja69d6F/Yih5qi32 -ukl8in2O7Nw3d8KtIvYacNyDq3T8XBDCk+rgU42B6BhA5ip1TrHaONaBzzxUBMfO -eQIDAQAB ------END PUBLIC KEY----- - diff --git a/.gitignore b/.gitignore index 0f3eafa..34feafc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ inst/doc /docs/ /vignettes/*.html /revdep/.cache.rds +.projectile diff --git a/.travis.yml b/.travis.yml index a4acac5..a563ea7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ # Header language: r sudo: false +dist: trusty cache: packages warnings_are_errors: true diff --git a/API b/API new file mode 100644 index 0000000..44004ea --- /dev/null +++ b/API @@ -0,0 +1,37 @@ +# API for rprojroot package + +## Exported functions + +as.root_criterion(x) +find_package_root_file(..., path = ".") +find_remake_root_file(..., path = ".") +find_root(criterion, path = ".") +find_root_file(..., criterion, path = ".") +find_rstudio_root_file(..., path = ".") +find_testthat_root_file(..., path = ".") +get_root_desc(criterion, path) +has_dir(filepath) +has_dirname(dirname, subdir = NULL) +has_file(filepath, contents = NULL, n = -1L) +has_file_pattern(pattern, contents = NULL, n = -1L) +is.root_criterion(x) +root_criterion(testfun, desc, subdir = NULL) + +## S3 methods + +as.root_criterion.character(x) +as.root_criterion.default(x) +as.root_criterion.root_criterion(x) + +## Exported data + +criteria: root_criteria (list[9]) +from_wd: root_criterion (list[5]) +is_git_root: root_criterion (list[5]) +is_projectile_project: root_criterion (list[5]) +is_r_package: root_criterion (list[5]) +is_remake_project: root_criterion (list[5]) +is_rstudio_project: root_criterion (list[5]) +is_svn_root: root_criterion (list[5]) +is_testthat: root_criterion (list[5]) +is_vcs_root: root_criterion (list[5]) diff --git a/DESCRIPTION b/DESCRIPTION index 2e515ca..0924fe0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: rprojroot Title: Finding Files in Project Subdirectories -Version: 1.1 +Version: 1.2 Authors@R: person(given = "Kirill", family = "Müller", role = c("aut", "cre"), email = "krlmlr+r@mailbox.org") Description: Robust, reliable and flexible paths to files below a @@ -31,3 +31,4 @@ Collate: 'root.R' 'rprojroot-package.R' 'shortcut.R' +Roxygen: list(markdown = TRUE) diff --git a/NAMESPACE b/NAMESPACE index 1773a49..9dafdaf 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -16,14 +16,20 @@ export(find_root_file) export(find_rstudio_root_file) export(find_testthat_root_file) export(from_wd) +export(get_root_desc) +export(has_dir) export(has_dirname) export(has_file) export(has_file_pattern) export(is.root_criterion) +export(is_git_root) +export(is_projectile_project) export(is_r_package) export(is_remake_project) export(is_rstudio_project) +export(is_svn_root) export(is_testthat) +export(is_vcs_root) export(root_criterion) import(backports) importFrom(utils,str) diff --git a/NEWS.md b/NEWS.md index 6b0068e..18da147 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,21 @@ +# rprojroot 1.2 (2017-01-15) + +- New root criteria + - `is_projectile_project` recognize projectile projects (#21). + - `has_dir()` constructs root criteria that check for existence of a directory. + - `is_git_root`, `is_svn_root` and `is_vcs_root` look for a version control system root (#19). + +- New function + - `get_root_desc()` returns the description of the criterion that applies to a given root, useful for composite criteria created with `|`. + +- Minor enhancements + - Improve formatting of alternative criteria (#18). + - If root cannot be found, the start path is shown in the error message. + +- Internal + - The `$testfun` member of the `rprojroot` S3 class is now a list of functions instead of a function. + + # rprojroot 1.1 (2016-10-29) - Compatibility diff --git a/R/criterion.R b/R/criterion.R index 3af337b..35dd60c 100644 --- a/R/criterion.R +++ b/R/criterion.R @@ -1,25 +1,26 @@ #' Is a directory the project root? #' -#' Objects of the \code{root_criterion} class decide if a +#' Objects of the `root_criterion` class decide if a #' given directory is a project root. #' -#' Construct criteria using \code{root_criterion} in a very general fashion -#' by specifying a function with a \code{path} argument, and a description. +#' Construct criteria using `root_criterion` in a very general fashion +#' by specifying a function with a `path` argument, and a description. #' -#' @param testfun A function with one parameter that returns \code{TRUE} +#' @param testfun A function with one parameter that returns `TRUE` #' if the directory specified by this parameter is the project root, -#' and \code{FALSE} otherwise -#' @param desc A textual description of the test criterion +#' and `FALSE` otherwise. Can also be a list of such functions. +#' @param desc A textual description of the test criterion, of the same length +#' as `testfun` #' @param subdir Subdirectories to start the search in, if found #' #' @return -#' An S3 object of class \code{root_criterion} wit the following members: +#' An S3 object of class `root_criterion` wit the following members: #' #' @include rrmake.R #' @export #' #' @examples -#' root_criterion(function(path) file.exists(file.path(path, "somefile")), "Has somefile") +#' root_criterion(function(path) file.exists(file.path(path, "somefile")), "has somefile") #' has_file("DESCRIPTION") #' is_r_package #' is_r_package$find_file @@ -27,15 +28,15 @@ #' is_r_package$make_fix_file(".") #' } root_criterion <- function(testfun, desc, subdir = NULL) { - if (!isTRUE(all.equal(names(formals(testfun)), "path"))) { - stop("testfun must be a function with one argument 'path'") - } + testfun <- check_testfun(testfun) + + stopifnot(length(desc) == length(testfun)) full_desc <- paste0( desc, if (!is.null(subdir)) paste0( " (also look in subdirectories: ", - paste0("'", subdir, "'", collapse = ", "), + paste0("`", subdir, "`", collapse = ", "), ")" ) ) @@ -44,27 +45,27 @@ root_criterion <- function(testfun, desc, subdir = NULL) { list( #' @return #' \describe{ - #' \item{\code{testfun}}{The \code{testfun} argument} + #' \item{`testfun`}{The `testfun` argument} testfun = testfun, - #' \item{\code{desc}}{The \code{desc} argument} + #' \item{`desc`}{The `desc` argument} desc = full_desc, - #' \item{\code{subdir}}{The \code{subdir} argument} + #' \item{`subdir`}{The `subdir` argument} subdir = subdir ), class = "root_criterion" ) - #' \item{\code{find_file}}{A function with \code{...} argument that returns + #' \item{`find_file`}{A function with `...` argument that returns #' for a path relative to the root specified by this criterion. - #' The optional \code{path} argument specifies the starting directory, - #' which defaults to \code{"."}. + #' The optional `path` argument specifies the starting directory, + #' which defaults to `"."`. #' } criterion$find_file <- make_find_root_file(criterion) - #' \item{\code{make_fix_file}}{A function with a \code{path} argument that + #' \item{`make_fix_file`}{A function with a `path` argument that #' returns a function that finds paths relative to the root. For a - #' criterion \code{cr}, the result of \code{cr$make_fix_file(".")(...)} - #' is identical to \code{cr$find_file(...)}. The function created by - #' \code{make_fix_file} can be saved to a variable to be more independent + #' criterion `cr`, the result of `cr$make_fix_file(".")(...)` + #' is identical to `cr$find_file(...)`. The function created by + #' `make_fix_file` can be saved to a variable to be more independent #' of the current working directory. #' } #' } @@ -74,6 +75,20 @@ root_criterion <- function(testfun, desc, subdir = NULL) { criterion } +check_testfun <- function(testfun) { + if (is.function(testfun)) { + testfun <- list(testfun) + } + + for (f in testfun) { + if (!isTRUE(all.equal(names(formals(f)), "path"))) { + stop("All functions in testfun must have exactly one argument 'path'") + } + } + + testfun +} + #' @rdname root_criterion #' @param x An object #' @export @@ -86,9 +101,9 @@ is.root_criterion <- function(x) { as.root_criterion <- function(x) UseMethod("as.root_criterion", x) #' @details -#' The \code{as.root_criterion} function accepts objects of class -#' \code{root_criterion}, and character values; the latter will be -#' converted to criteria using \code{has_file}. +#' The `as.root_criterion` function accepts objects of class +#' `root_criterion`, and character values; the latter will be +#' converted to criteria using `has_file`. #' #' @rdname root_criterion #' @export @@ -107,20 +122,30 @@ as.root_criterion.default <- function(x) { #' @export format.root_criterion <- function(x, ...) { - paste("Root criterion:", x$desc) + if (length(x$desc) > 1) { + c("Root criterion: one of", paste0("- ", x$desc)) + } else { + paste0("Root criterion: ", x$desc) + } } #' @export print.root_criterion <- function(x, ...) { - cat(paste0(format(x), "\n")) + cat(format(x), sep = "\n") + invisible(x) } #' @export +#' @rdname root_criterion +#' @details Root criteria can be combined with the `|` operator. The result is a +#' composite root criterion that requires either of the original criteria to +#' match. +#' @param y An object `|.root_criterion` <- function(x, y) { stopifnot(is.root_criterion(y)) root_criterion( - function(path) x$testfun(path) || y$testfun(path), - paste0(x$desc, ", or ", y$desc) + c(x$testfun, y$testfun), + c(x$desc, y$desc) ) } diff --git a/R/file.R b/R/file.R index a1e44bb..45ad46f 100644 --- a/R/file.R +++ b/R/file.R @@ -1,17 +1,17 @@ #' File paths relative to the root of a directory hierarchy #' #' Append an arbitrary number of path components to the root using -#' \code{\link[base]{file.path}}. +#' [base::file.path()]. #' -#' The \code{find_root_file} function is a simple wrapper around -#' \code{\link{find_root}} that +#' The `find_root_file` function is a simple wrapper around +#' [find_root()] that #' appends an arbitrary number of path components to the root using -#' \code{\link[base]{file.path}}. +#' [base::file.path()]. #' #' @param criterion A criterion, will be coerced using -#' \code{\link{as.root_criterion}} +#' [as.root_criterion()] #' @param path The start directory -#' @param ... Further path components passed to \code{\link{file.path}} +#' @param ... Further path components passed to [file.path()] #' @return The normalized path of the root as specified by the search criteria, #' with the additional path components appended. #' Throws an error if no root is found @@ -23,7 +23,7 @@ #' has_file("DESCRIPTION", "^Package: ")$make_fix_file(".") #' } #' -#' @seealso \code{\link{find_root}} \code{\link[utils]{glob2rx}} \code{\link[base]{file.path}} +#' @seealso [find_root()] [utils::glob2rx()] [base::file.path()] #' #' @export find_root_file <- function(..., criterion, path = ".") { diff --git a/R/has-file.R b/R/has-file.R index 04f1bfe..a03251c 100644 --- a/R/has-file.R +++ b/R/has-file.R @@ -1,5 +1,9 @@ +format_lines <- function(n) { + if (n == 1) "line" else paste0(n, " lines") +} + #' @details -#' The \code{has_file} function constructs a criterion that checks for the +#' The `has_file` function constructs a criterion that checks for the #' existence of a specific file (which itself can be in a subdirectory of the #' root) with specific contents. #' @@ -23,17 +27,38 @@ has_file <- function(filepath, contents = NULL, n = -1L) { })) desc <- paste0( - "Contains a file '", filepath, "'", + "contains a file `", filepath, "`", if (!is.null(contents)) { - paste0(" with contents matching '", contents, "'", - if (n >= 0L) paste(" in the first", n, "lines")) + paste0(" with contents matching `", contents, "`", + if (n >= 0L) paste0(" in the first ", format_lines(n))) }) root_criterion(testfun, desc) } #' @details -#' The \code{has_file_pattern} function constructs a criterion that checks for the +#' The `has_dir` function constructs a criterion that checks for the +#' existence of a specific directory. +#' +#' @rdname root_criterion +#' @export +has_dir <- function(filepath) { + force(filepath) + + testfun <- eval(bquote(function(path) { + testfile <- file.path(path, .(filepath)) + if (!file.exists(testfile)) + return(FALSE) + is_dir(testfile) + })) + + desc <- paste0("contains a directory `", filepath, "`") + + root_criterion(testfun, desc) +} + +#' @details +#' The `has_file_pattern` function constructs a criterion that checks for the #' existence of a file that matches a pattern, with specific contents. #' #' @rdname root_criterion @@ -57,18 +82,18 @@ has_file_pattern <- function(pattern, contents = NULL, n = -1L) { })) desc <- paste0( - "Contains a file matching '", pattern, "'", + "contains a file matching `", pattern, "`", if (!is.null(contents)) { - paste0(" with contents matching '", contents, "'", - if (n >= 0L) paste(" in the first", n, "lines")) + paste0(" with contents matching `", contents, "`", + if (n >= 0L) paste0(" in the first ", format_lines(n))) }) root_criterion(testfun, desc) } #' @details -#' The \code{has_dirname} function constructs a criterion that checks if the -#' \code{\link[base]{dirname}} has a specific name. +#' The `has_dirname` function constructs a criterion that checks if the +#' [base::dirname()] has a specific name. #' #' @rdname root_criterion #' @param dirname A directory name, without subdirectories @@ -80,7 +105,7 @@ has_dirname <- function(dirname, subdir = NULL) { dir.exists(file.path(dirname(path), .(dirname))) })) - desc <- paste0("Directory name is '", dirname, "'") + desc <- paste0("directory name is `", dirname, "`") root_criterion(testfun, desc, subdir = subdir) } @@ -95,11 +120,23 @@ is_r_package <- has_file("DESCRIPTION", contents = "^Package: ") is_remake_project <- has_file("remake.yml") #' @export -from_wd <- root_criterion(function(path) TRUE, "From current working directory") +is_projectile_project <- has_file(".projectile") + +#' @export +is_git_root <- has_dir(".git") + +#' @export +is_svn_root <- has_dir(".svn") + +#' @export +is_vcs_root <- is_git_root | is_svn_root #' @export is_testthat <- has_dirname("testthat", c("tests/testthat", "testthat")) +#' @export +from_wd <- root_criterion(function(path) TRUE, "from current working directory") + #' Prespecified criteria #' #' This is a collection of commonly used root criteria. @@ -110,6 +147,10 @@ criteria <- structure( is_rstudio_project = is_rstudio_project, is_r_package = is_r_package, is_remake_project = is_remake_project, + is_projectile_project = is_projectile_project, + is_git_root = is_git_root, + is_svn_root = is_svn_root, + is_vcs_root = is_vcs_root, is_testthat = is_testthat, from_wd = from_wd ), @@ -122,28 +163,57 @@ str.root_criteria <- function(object, ...) { } #' @details -#' \code{is_rstudio_project} looks for a file with extension \code{.Rproj}. +#' `is_rstudio_project` looks for a file with extension `.Rproj`. #' #' @rdname criteria #' @export "is_rstudio_project" #' @details -#' \code{is_r_package} looks for a \code{DESCRIPTION} file. +#' `is_r_package` looks for a `DESCRIPTION` file. #' #' @rdname criteria #' @export "is_r_package" #' @details -#' \code{is_remake_project} looks for a \code{remake.yml} file. +#' `is_remake_project` looks for a `remake.yml` file. #' #' @rdname criteria #' @export "is_remake_project" #' @details -#' \code{is_testthat} looks for the \code{testthat} directory, works when +#' `is_projectile_project` looks for a `.projectile` file. +#' +#' @rdname criteria +#' @export +"is_projectile_project" + +#' @details +#' `is_git_project` looks for a `.git` directory. +#' +#' @rdname criteria +#' @export +"is_git_root" + +#' @details +#' `is_svn_project` looks for a `.svn` directory. +#' +#' @rdname criteria +#' @export +"is_svn_root" + +#' @details +#' `is_vcs_project` looks for the root of a version control +#' system, currently only Git and SVN are supported. +#' +#' @rdname criteria +#' @export +"is_vcs_root" + +#' @details +#' `is_testthat` looks for the `testthat` directory, works when #' developing, testing, and checking a package. #' #' @rdname criteria @@ -151,7 +221,7 @@ str.root_criteria <- function(object, ...) { "is_testthat" #' @details -#' \code{from_wd} uses the current working directory. +#' `from_wd` uses the current working directory. #' #' @rdname criteria #' @export diff --git a/R/root.R b/R/root.R index d52a332..4ab40ff 100644 --- a/R/root.R +++ b/R/root.R @@ -5,9 +5,9 @@ #' The search for a root starts at a given directory (the working directory #' by default), and proceeds up the directory hierarchy. #' -#' Starting from the working directory, the \code{find_root} function searches +#' Starting from the working directory, the `find_root` function searches #' for the root. -#' If a root is found, the \code{...} arguments are used to construct a path; +#' If a root is found, the `...` arguments are used to construct a path; #' thus, if no extra arguments are given, the root is returned. #' If no root is found, an error is thrown. #' @@ -20,22 +20,25 @@ #' find_root(glob2rx("DESCRIPTION"), "^Package: ") #' } #' -#' @seealso \code{\link[utils]{glob2rx}} \code{\link{file.path}} +#' @seealso [utils::glob2rx()] [file.path()] #' #' @export find_root <- function(criterion, path = ".") { criterion <- as.root_criterion(criterion) - path <- start_path(path, criterion$subdir) + start_path <- get_start_path(path, criterion$subdir) + path <- start_path for (i in seq_len(.MAX_DEPTH)) { - if (criterion$testfun(path)) { - return(path) + for (f in criterion$testfun) { + if (f(path)) { + return(path) + } } if (is_root(path)) { - stop("No root directory found. Test criterion:\n", - criterion$desc, call. = FALSE) + stop("No root directory found in ", start_path, " or its parent directories. ", + paste(format(criterion), collapse = "\n"), call. = FALSE) } path <- dirname(path) @@ -46,7 +49,7 @@ find_root <- function(criterion, path = ".") { .MAX_DEPTH <- 100L -start_path <- function(path, subdirs) { +get_start_path <- function(path, subdirs) { path <- normalizePath(path, winslash = "/", mustWork = TRUE) for (subdir in subdirs) { @@ -64,3 +67,19 @@ is_root <- function(path) { identical(normalizePath(path, winslash = "/"), normalizePath(dirname(path), winslash = "/")) } + +#' @rdname find_root +#' @description `get_root_desc()` returns the description of the criterion +#' for a root path. This is especially useful for composite root criteria +#' created with [|.root_criterion()]. +#' @export +get_root_desc <- function(criterion, path) { + for (i in seq_along(criterion$testfun)) { + if (criterion$testfun[[i]](path)) { + return(criterion$desc[[i]]) + } + } + + stop("path is not a root. ", + paste(format(criterion), collapse = "\n"), call. = FALSE) +} diff --git a/R/rprojroot-package.R b/R/rprojroot-package.R index 8f38d4f..d427a00 100644 --- a/R/rprojroot-package.R +++ b/R/rprojroot-package.R @@ -1,6 +1,6 @@ #' @details -#' See the "Value" section in \code{\link{root_criterion}} for documentation -#' of root criterion objects, and \code{\link{criteria}} for useful predefined +#' See the "Value" section in [root_criterion()] for documentation +#' of root criterion objects, and [criteria()] for useful predefined #' root criteria. #' #' @examples @@ -11,4 +11,5 @@ #' root_fun("NAMESPACE") #' } #' @import backports +#' @api "_PACKAGE" diff --git a/cran-comments.md b/cran-comments.md index 2e72a56..5ce9e4c 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,6 +1,6 @@ ## Test environments -* local Ubuntu install, R 3.3.1 -* ubuntu 12.04 (on travis-ci, R devel, release, and oldrel) +* local Ubuntu install, R 3.3.2 +* ubuntu 14.04 (on travis-ci, R devel, release, and oldrel) * OS X (on travis-ci, R release) win-builder (devel and release) @@ -9,9 +9,7 @@ OK -* I don't see the warnings on R-devel with the updated version anymore. - ## Reverse dependencies -* I have run R CMD check on the 2 downstream dependencies, both were OK. +* I have run R CMD check on the 3 downstream dependencies, all were OK. diff --git a/man/criteria.Rd b/man/criteria.Rd index a2e096c..d8ad0ef 100644 --- a/man/criteria.Rd +++ b/man/criteria.Rd @@ -3,13 +3,17 @@ \docType{data} \name{criteria} \alias{criteria} -\alias{from_wd} +\alias{is_rstudio_project} \alias{is_r_package} \alias{is_remake_project} -\alias{is_rstudio_project} +\alias{is_projectile_project} +\alias{is_git_root} +\alias{is_svn_root} +\alias{is_vcs_root} \alias{is_testthat} +\alias{from_wd} \title{Prespecified criteria} -\format{An object of class \code{root_criteria} of length 5.} +\format{An object of class \code{root_criteria} of length 9.} \usage{ criteria @@ -19,6 +23,14 @@ is_r_package is_remake_project +is_projectile_project + +is_git_root + +is_svn_root + +is_vcs_root + is_testthat from_wd @@ -33,10 +45,18 @@ This is a collection of commonly used root criteria. \code{is_remake_project} looks for a \code{remake.yml} file. +\code{is_projectile_project} looks for a \code{.projectile} file. + +\code{is_git_project} looks for a \code{.git} directory. + +\code{is_svn_project} looks for a \code{.svn} directory. + +\code{is_vcs_project} looks for the root of a version control +system, currently only Git and SVN are supported. + \code{is_testthat} looks for the \code{testthat} directory, works when - developing, testing, and checking a package. +developing, testing, and checking a package. \code{from_wd} uses the current working directory. } \keyword{datasets} - diff --git a/man/find_root.Rd b/man/find_root.Rd index 6b7d3ee..9f2c085 100644 --- a/man/find_root.Rd +++ b/man/find_root.Rd @@ -2,25 +2,32 @@ % Please edit documentation in R/root.R \name{find_root} \alias{find_root} +\alias{get_root_desc} \title{Find the root of a directory hierarchy} \usage{ find_root(criterion, path = ".") + +get_root_desc(criterion, path) } \arguments{ \item{criterion}{A criterion, will be coerced using -\code{\link{as.root_criterion}}} +\code{\link[=as.root_criterion]{as.root_criterion()}}} \item{path}{The start directory} } \value{ The normalized path of the root as specified by the search criterion. - Throws an error if no root is found +Throws an error if no root is found } \description{ A \emph{root} is defined as a directory that contains a regular file whose name matches a given pattern and which optionally contains a given text. The search for a root starts at a given directory (the working directory by default), and proceeds up the directory hierarchy. + +\code{get_root_desc()} returns the description of the criterion +for a root path. This is especially useful for composite root criteria +created with \code{\link[=|.root_criterion]{|.root_criterion()}}. } \details{ Starting from the working directory, the \code{find_root} function searches @@ -36,6 +43,5 @@ find_root(glob2rx("DESCRIPTION"), "^Package: ") } \seealso{ -\code{\link[utils]{glob2rx}} \code{\link{file.path}} +\code{\link[utils:glob2rx]{utils::glob2rx()}} \code{\link[=file.path]{file.path()}} } - diff --git a/man/find_root_file.Rd b/man/find_root_file.Rd index 9a1a706..c97d51e 100644 --- a/man/find_root_file.Rd +++ b/man/find_root_file.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/file.R, R/shortcut.R \name{find_root_file} -\alias{find_package_root_file} -\alias{find_remake_root_file} \alias{find_root_file} \alias{find_rstudio_root_file} +\alias{find_package_root_file} +\alias{find_remake_root_file} \alias{find_testthat_root_file} \title{File paths relative to the root of a directory hierarchy} \usage{ @@ -19,27 +19,27 @@ find_remake_root_file(..., path = ".") find_testthat_root_file(..., path = ".") } \arguments{ -\item{...}{Further path components passed to \code{\link{file.path}}} +\item{...}{Further path components passed to \code{\link[=file.path]{file.path()}}} \item{criterion}{A criterion, will be coerced using -\code{\link{as.root_criterion}}} +\code{\link[=as.root_criterion]{as.root_criterion()}}} \item{path}{The start directory} } \value{ The normalized path of the root as specified by the search criteria, - with the additional path components appended. - Throws an error if no root is found +with the additional path components appended. +Throws an error if no root is found } \description{ Append an arbitrary number of path components to the root using -\code{\link[base]{file.path}}. +\code{\link[base:file.path]{base::file.path()}}. } \details{ The \code{find_root_file} function is a simple wrapper around -\code{\link{find_root}} that +\code{\link[=find_root]{find_root()}} that appends an arbitrary number of path components to the root using -\code{\link[base]{file.path}}. +\code{\link[base:file.path]{base::file.path()}}. } \examples{ \dontrun{ @@ -50,6 +50,5 @@ has_file("DESCRIPTION", "^Package: ")$make_fix_file(".") } \seealso{ -\code{\link{find_root}} \code{\link[utils]{glob2rx}} \code{\link[base]{file.path}} +\code{\link[=find_root]{find_root()}} \code{\link[utils:glob2rx]{utils::glob2rx()}} \code{\link[base:file.path]{base::file.path()}} } - diff --git a/man/root_criterion.Rd b/man/root_criterion.Rd index 1320e93..d47d910 100644 --- a/man/root_criterion.Rd +++ b/man/root_criterion.Rd @@ -1,14 +1,16 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/criterion.R, R/has-file.R \name{root_criterion} +\alias{root_criterion} +\alias{is.root_criterion} \alias{as.root_criterion} \alias{as.root_criterion.character} \alias{as.root_criterion.root_criterion} -\alias{has_dirname} +\alias{|.root_criterion} \alias{has_file} +\alias{has_dir} \alias{has_file_pattern} -\alias{is.root_criterion} -\alias{root_criterion} +\alias{has_dirname} \title{Is a directory the project root?} \usage{ root_criterion(testfun, desc, subdir = NULL) @@ -21,8 +23,12 @@ as.root_criterion(x) \method{as.root_criterion}{root_criterion}(x) +\method{|}{root_criterion}(x, y) + has_file(filepath, contents = NULL, n = -1L) +has_dir(filepath) + has_file_pattern(pattern, contents = NULL, n = -1L) has_dirname(dirname, subdir = NULL) @@ -30,14 +36,17 @@ has_dirname(dirname, subdir = NULL) \arguments{ \item{testfun}{A function with one parameter that returns \code{TRUE} if the directory specified by this parameter is the project root, -and \code{FALSE} otherwise} +and \code{FALSE} otherwise. Can also be a list of such functions.} -\item{desc}{A textual description of the test criterion} +\item{desc}{A textual description of the test criterion, of the same length +as \code{testfun}} \item{subdir}{Subdirectories to start the search in, if found} \item{x}{An object} +\item{y}{An object} + \item{filepath}{File path (can contain directories)} \item{contents}{Regular expression to match the file contents} @@ -54,21 +63,21 @@ and \code{FALSE} otherwise} An S3 object of class \code{root_criterion} wit the following members: \describe{ - \item{\code{testfun}}{The \code{testfun} argument} - \item{\code{desc}}{The \code{desc} argument} - \item{\code{subdir}}{The \code{subdir} argument} - \item{\code{find_file}}{A function with \code{...} argument that returns - for a path relative to the root specified by this criterion. - The optional \code{path} argument specifies the starting directory, - which defaults to \code{"."}. - } - \item{\code{make_fix_file}}{A function with a \code{path} argument that - returns a function that finds paths relative to the root. For a - criterion \code{cr}, the result of \code{cr$make_fix_file(".")(...)} - is identical to \code{cr$find_file(...)}. The function created by - \code{make_fix_file} can be saved to a variable to be more independent - of the current working directory. - } +\item{\code{testfun}}{The \code{testfun} argument} +\item{\code{desc}}{The \code{desc} argument} +\item{\code{subdir}}{The \code{subdir} argument} +\item{\code{find_file}}{A function with \code{...} argument that returns +for a path relative to the root specified by this criterion. +The optional \code{path} argument specifies the starting directory, +which defaults to \code{"."}. +} +\item{\code{make_fix_file}}{A function with a \code{path} argument that +returns a function that finds paths relative to the root. For a +criterion \code{cr}, the result of \code{cr$make_fix_file(".")(...)} +is identical to \code{cr$find_file(...)}. The function created by +\code{make_fix_file} can be saved to a variable to be more independent +of the current working directory. +} } } \description{ @@ -83,18 +92,25 @@ The \code{as.root_criterion} function accepts objects of class \code{root_criterion}, and character values; the latter will be converted to criteria using \code{has_file}. +Root criteria can be combined with the \code{|} operator. The result is a +composite root criterion that requires either of the original criteria to +match. + The \code{has_file} function constructs a criterion that checks for the existence of a specific file (which itself can be in a subdirectory of the root) with specific contents. +The \code{has_dir} function constructs a criterion that checks for the +existence of a specific directory. + The \code{has_file_pattern} function constructs a criterion that checks for the existence of a file that matches a pattern, with specific contents. The \code{has_dirname} function constructs a criterion that checks if the -\code{\link[base]{dirname}} has a specific name. +\code{\link[base:dirname]{base::dirname()}} has a specific name. } \examples{ -root_criterion(function(path) file.exists(file.path(path, "somefile")), "Has somefile") +root_criterion(function(path) file.exists(file.path(path, "somefile")), "has somefile") has_file("DESCRIPTION") is_r_package is_r_package$find_file @@ -102,4 +118,3 @@ is_r_package$find_file is_r_package$make_fix_file(".") } } - diff --git a/man/rprojroot-package.Rd b/man/rprojroot-package.Rd index ce42a68..4090994 100644 --- a/man/rprojroot-package.Rd +++ b/man/rprojroot-package.Rd @@ -4,7 +4,7 @@ \name{rprojroot-package} \alias{rprojroot} \alias{rprojroot-package} -\title{Finding Files in Project Subdirectories} +\title{rprojroot: Finding Files in Project Subdirectories} \description{ Robust, reliable and flexible paths to files below a project root. The 'root' of a project is defined as a directory @@ -12,8 +12,8 @@ that matches a certain criterion, e.g., it contains a certain regular file. } \details{ -See the "Value" section in \code{\link{root_criterion}} for documentation -of root criterion objects, and \code{\link{criteria}} for useful predefined +See the "Value" section in \code{\link[=root_criterion]{root_criterion()}} for documentation +of root criterion objects, and \code{\link[=criteria]{criteria()}} for useful predefined root criteria. } \examples{ @@ -24,4 +24,16 @@ root_fun <- is_r_package$make_fix_file() root_fun("NAMESPACE") } } +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/krlmlr/rprojroot} + \item \url{https://krlmlr.github.io/rprojroot} + \item Report bugs at \url{https://github.com/krlmlr/rprojroot/issues} +} + +} +\author{ +\strong{Maintainer}: Kirill Müller \email{krlmlr+r@mailbox.org} +} diff --git a/revdep/README-r-1.2.md b/revdep/README-r-1.2.md new file mode 100644 index 0000000..9c59634 --- /dev/null +++ b/revdep/README-r-1.2.md @@ -0,0 +1,59 @@ +# Setup + +## Platform + +|setting |value | +|:--------|:----------------------------| +|version |R version 3.3.2 (2016-10-31) | +|system |x86_64, linux-gnu | +|ui |X11 | +|language |(EN) | +|collate |en_US.UTF-8 | +|tz |Zulu | +|date |2017-01-15 | + +## Packages + +|package |* |version |date |source | +|:---------|:--|:----------|:----------|:--------------------------------| +|backports | |1.0.4 |2016-10-24 |cran (@1.0.4) | +|knitr | |1.15.1 |2016-11-22 |cran (@1.15.1) | +|rmarkdown | |1.3 |2016-12-21 |cran (@1.3) | +|rprojroot | |1.1 |2016-10-29 |cran (@1.1) | +|testthat | |1.0.2.9000 |2016-12-24 |Github (hadley/testthat@3b2f225) | +|withr | |1.0.2 |2016-06-20 |CRAN (R 3.3.1) | + +# Check results + +3 packages + +|package |version | errors| warnings| notes| +|:------------|:-------|------:|--------:|-----:| +|googlesheets |0.2.1 | 0| 0| 0| +|rmarkdown |1.3 | 0| 0| 1| +|sparklyr |0.5.1 | 0| 0| 0| + +## googlesheets (0.2.1) +Maintainer: Jennifer Bryan +Bug reports: https://github.com/jennybc/googlesheets/issues + +0 errors | 0 warnings | 0 notes + +## rmarkdown (1.3) +Maintainer: JJ Allaire + +0 errors | 0 warnings | 1 note + +``` +checking installed package size ... NOTE + installed size is 6.6Mb + sub-directories of 1Mb or more: + rmd 6.1Mb +``` + +## sparklyr (0.5.1) +Maintainer: Javier Luraschi +Bug reports: https://github.com/rstudio/sparklyr/issues + +0 errors | 0 warnings | 0 notes + diff --git a/revdep/README-v1.1.md b/revdep/README-v1.1.md new file mode 100644 index 0000000..9c59634 --- /dev/null +++ b/revdep/README-v1.1.md @@ -0,0 +1,59 @@ +# Setup + +## Platform + +|setting |value | +|:--------|:----------------------------| +|version |R version 3.3.2 (2016-10-31) | +|system |x86_64, linux-gnu | +|ui |X11 | +|language |(EN) | +|collate |en_US.UTF-8 | +|tz |Zulu | +|date |2017-01-15 | + +## Packages + +|package |* |version |date |source | +|:---------|:--|:----------|:----------|:--------------------------------| +|backports | |1.0.4 |2016-10-24 |cran (@1.0.4) | +|knitr | |1.15.1 |2016-11-22 |cran (@1.15.1) | +|rmarkdown | |1.3 |2016-12-21 |cran (@1.3) | +|rprojroot | |1.1 |2016-10-29 |cran (@1.1) | +|testthat | |1.0.2.9000 |2016-12-24 |Github (hadley/testthat@3b2f225) | +|withr | |1.0.2 |2016-06-20 |CRAN (R 3.3.1) | + +# Check results + +3 packages + +|package |version | errors| warnings| notes| +|:------------|:-------|------:|--------:|-----:| +|googlesheets |0.2.1 | 0| 0| 0| +|rmarkdown |1.3 | 0| 0| 1| +|sparklyr |0.5.1 | 0| 0| 0| + +## googlesheets (0.2.1) +Maintainer: Jennifer Bryan +Bug reports: https://github.com/jennybc/googlesheets/issues + +0 errors | 0 warnings | 0 notes + +## rmarkdown (1.3) +Maintainer: JJ Allaire + +0 errors | 0 warnings | 1 note + +``` +checking installed package size ... NOTE + installed size is 6.6Mb + sub-directories of 1Mb or more: + rmd 6.1Mb +``` + +## sparklyr (0.5.1) +Maintainer: Javier Luraschi +Bug reports: https://github.com/rstudio/sparklyr/issues + +0 errors | 0 warnings | 0 notes + diff --git a/revdep/README.md b/revdep/README.md index 3015507..9c59634 100644 --- a/revdep/README.md +++ b/revdep/README.md @@ -4,33 +4,34 @@ |setting |value | |:--------|:----------------------------| -|version |R version 3.3.1 (2016-06-21) | +|version |R version 3.3.2 (2016-10-31) | |system |x86_64, linux-gnu | |ui |X11 | -|language |en_US:en | +|language |(EN) | |collate |en_US.UTF-8 | -|tz |Europe/Busingen | -|date |2016-10-29 | +|tz |Zulu | +|date |2017-01-15 | ## Packages -|package |* |version |date |source | -|:---------|:--|:-------|:----------|:---------------------------| -|backports | |1.0.3 |2016-06-28 |cran (@1.0.3) | -|knitr | |1.14 |2016-08-13 |cran (@1.14) | -|rmarkdown | |1.0 |2016-07-08 |cran (@1.0) | -|rprojroot | |1.1 |2016-10-29 |local (krlmlr/rprojroot@NA) | -|testthat | |1.0.2 |2016-04-23 |cran (@1.0.2) | -|withr | |1.0.2 |2016-06-20 |cran (@1.0.2) | +|package |* |version |date |source | +|:---------|:--|:----------|:----------|:--------------------------------| +|backports | |1.0.4 |2016-10-24 |cran (@1.0.4) | +|knitr | |1.15.1 |2016-11-22 |cran (@1.15.1) | +|rmarkdown | |1.3 |2016-12-21 |cran (@1.3) | +|rprojroot | |1.1 |2016-10-29 |cran (@1.1) | +|testthat | |1.0.2.9000 |2016-12-24 |Github (hadley/testthat@3b2f225) | +|withr | |1.0.2 |2016-06-20 |CRAN (R 3.3.1) | # Check results -2 packages +3 packages |package |version | errors| warnings| notes| |:------------|:-------|------:|--------:|-----:| |googlesheets |0.2.1 | 0| 0| 0| -|sparklyr |0.4 | 0| 0| 0| +|rmarkdown |1.3 | 0| 0| 1| +|sparklyr |0.5.1 | 0| 0| 0| ## googlesheets (0.2.1) Maintainer: Jennifer Bryan @@ -38,7 +39,19 @@ Bug reports: https://github.com/jennybc/googlesheets/issues 0 errors | 0 warnings | 0 notes -## sparklyr (0.4) +## rmarkdown (1.3) +Maintainer: JJ Allaire + +0 errors | 0 warnings | 1 note + +``` +checking installed package size ... NOTE + installed size is 6.6Mb + sub-directories of 1Mb or more: + rmd 6.1Mb +``` + +## sparklyr (0.5.1) Maintainer: Javier Luraschi Bug reports: https://github.com/rstudio/sparklyr/issues diff --git a/revdep/checks.rds b/revdep/checks.rds index bf6740f..f6293ca 100644 Binary files a/revdep/checks.rds and b/revdep/checks.rds differ diff --git a/revdep/diff.sh b/revdep/diff.sh new file mode 100755 index 0000000..07b9ef7 --- /dev/null +++ b/revdep/diff.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +set -e + +old_tag=v1.1 +branch=$(git symbolic-ref --short HEAD) +remote=$(git rev-parse --symbolic-full-name --abbrev-ref @{u} | cut -d "/" -f 1) + +cd $(dirname $0)/.. + +if [ "$old_tag" != "" ]; then + +git checkout -- . +git clean --force -dx + +git checkout $branch -- +cp -r revdep revdep- + +git checkout $old_tag -- +rm -rf revdep +mv revdep- revdep +rm -rf revdep/install + +git add revdep +git commit -m "revdep update for clean state" || true + +R -f revdep/check.R +#echo $old_tag >> revdep/README.md + +mv revdep revdep-$old_tag +git checkout . + +git checkout $branch -- + +rm -rf revdep +mv revdep-$old_tag revdep +cp revdep/README.md revdep/README-${old_tag}.md +cp revdep/problems.md revdep/problems-${old_tag}.md +git add revdep +git commit -m "revdep update with $old_tag results" + +fi # if [ "$old_tag" != "" ]; then + +git clean --force -dx +rm -rf revdep/install +git add revdep +git commit -m "revdep update for clean state" || true + +git fetch --all +git rebase +git push $remote HEAD + +R -f revdep/check.R +#echo $branch >> revdep/README.md + +cp revdep/README.md revdep/README-${branch}.md +cp revdep/problems.md revdep/problems-${branch}.md + +git add revdep +git commit -m "revdep update with $branch results" + +git fetch --all +git rebase +git push $remote HEAD diff --git a/revdep/problems-r-1.2.md b/revdep/problems-r-1.2.md new file mode 100644 index 0000000..5d6bc21 --- /dev/null +++ b/revdep/problems-r-1.2.md @@ -0,0 +1,32 @@ +# Setup + +## Platform + +|setting |value | +|:--------|:----------------------------| +|version |R version 3.3.2 (2016-10-31) | +|system |x86_64, linux-gnu | +|ui |X11 | +|language |(EN) | +|collate |en_US.UTF-8 | +|tz |Zulu | +|date |2017-01-15 | + +## Packages + +|package |* |version |date |source | +|:---------|:--|:----------|:----------|:--------------------------------| +|backports | |1.0.4 |2016-10-24 |cran (@1.0.4) | +|knitr | |1.15.1 |2016-11-22 |cran (@1.15.1) | +|rmarkdown | |1.3 |2016-12-21 |cran (@1.3) | +|rprojroot | |1.1 |2016-10-29 |cran (@1.1) | +|testthat | |1.0.2.9000 |2016-12-24 |Github (hadley/testthat@3b2f225) | +|withr | |1.0.2 |2016-06-20 |CRAN (R 3.3.1) | + +# Check results + +0 packages with problems + + + + diff --git a/revdep/problems-v1.1.md b/revdep/problems-v1.1.md new file mode 100644 index 0000000..5d6bc21 --- /dev/null +++ b/revdep/problems-v1.1.md @@ -0,0 +1,32 @@ +# Setup + +## Platform + +|setting |value | +|:--------|:----------------------------| +|version |R version 3.3.2 (2016-10-31) | +|system |x86_64, linux-gnu | +|ui |X11 | +|language |(EN) | +|collate |en_US.UTF-8 | +|tz |Zulu | +|date |2017-01-15 | + +## Packages + +|package |* |version |date |source | +|:---------|:--|:----------|:----------|:--------------------------------| +|backports | |1.0.4 |2016-10-24 |cran (@1.0.4) | +|knitr | |1.15.1 |2016-11-22 |cran (@1.15.1) | +|rmarkdown | |1.3 |2016-12-21 |cran (@1.3) | +|rprojroot | |1.1 |2016-10-29 |cran (@1.1) | +|testthat | |1.0.2.9000 |2016-12-24 |Github (hadley/testthat@3b2f225) | +|withr | |1.0.2 |2016-06-20 |CRAN (R 3.3.1) | + +# Check results + +0 packages with problems + + + + diff --git a/revdep/problems.md b/revdep/problems.md index dc119cb..5d6bc21 100644 --- a/revdep/problems.md +++ b/revdep/problems.md @@ -4,24 +4,24 @@ |setting |value | |:--------|:----------------------------| -|version |R version 3.3.1 (2016-06-21) | +|version |R version 3.3.2 (2016-10-31) | |system |x86_64, linux-gnu | |ui |X11 | -|language |en_US:en | +|language |(EN) | |collate |en_US.UTF-8 | -|tz |Europe/Busingen | -|date |2016-10-29 | +|tz |Zulu | +|date |2017-01-15 | ## Packages -|package |* |version |date |source | -|:---------|:--|:-------|:----------|:---------------------------| -|backports | |1.0.3 |2016-06-28 |cran (@1.0.3) | -|knitr | |1.14 |2016-08-13 |cran (@1.14) | -|rmarkdown | |1.0 |2016-07-08 |cran (@1.0) | -|rprojroot | |1.1 |2016-10-29 |local (krlmlr/rprojroot@NA) | -|testthat | |1.0.2 |2016-04-23 |cran (@1.0.2) | -|withr | |1.0.2 |2016-06-20 |cran (@1.0.2) | +|package |* |version |date |source | +|:---------|:--|:----------|:----------|:--------------------------------| +|backports | |1.0.4 |2016-10-24 |cran (@1.0.4) | +|knitr | |1.15.1 |2016-11-22 |cran (@1.15.1) | +|rmarkdown | |1.3 |2016-12-21 |cran (@1.3) | +|rprojroot | |1.1 |2016-10-29 |cran (@1.1) | +|testthat | |1.0.2.9000 |2016-12-24 |Github (hadley/testthat@3b2f225) | +|withr | |1.0.2 |2016-06-20 |CRAN (R 3.3.1) | # Check results diff --git a/revdep/timing.md b/revdep/timing.md index 4aa26ce..827cd6d 100644 --- a/revdep/timing.md +++ b/revdep/timing.md @@ -2,7 +2,8 @@ | |package |version | check_time| |:--|:------------|:-------|----------:| -|2 |sparklyr |0.4 | 34.4| -|1 |googlesheets |0.2.1 | 33.1| +|3 |sparklyr |0.5.1 | 26.7| +|2 |rmarkdown |1.3 | 21.4| +|1 |googlesheets |0.2.1 | 17.8| diff --git a/tests/testthat/hierarchy/a/remake.yml b/tests/testthat/hierarchy/a/remake.yml new file mode 100644 index 0000000..e69de29 diff --git a/tests/testthat/test-criterion.R b/tests/testthat/test-criterion.R index f1573b7..dc5dca8 100644 --- a/tests/testthat/test-criterion.R +++ b/tests/testthat/test-criterion.R @@ -1,8 +1,8 @@ context("criterion") -test_that(".root_criterion", { - expect_error(root_criterion(5, "Bogus"), "must be a function with one argument") - expect_error(root_criterion(identity, "Bogus"), "must be a function with one argument") +test_that("root_criterion", { + expect_error(root_criterion(5, "Bogus"), "must have exactly one argument") + expect_error(root_criterion(identity, "Bogus"), "must have exactly one argument") expect_true(is.root_criterion(root_criterion(function(path) FALSE, "Never"))) }) @@ -20,8 +20,10 @@ test_that("Absolute paths are returned", { }) test_that("Formatting", { - expect_match(format(is_r_package), "^Root criterion: .*DESCRIPTION") + expect_match(paste(format(is_r_package), collapse = "\n"), + "^Root criterion: .*DESCRIPTION") expect_output(print(is_r_package), "^Root criterion: .*DESCRIPTION") + expect_output(print(is_vcs_root), "^Root criterion: one of\n- .*[.]git.*\n- .*[.]svn") }) test_that("Formatting criteria", { @@ -40,8 +42,8 @@ test_that("Combining criteria", { expect_true(is.root_criterion(comb_crit)) - expect_match(format(comb_crit), ", or") + expect_match(paste0(format(comb_crit), collapse = "\n"), "\n- .*\n- ") expect_equal(find_root(comb_crit, "hierarchy"), - find_root(is_rstudio_project | is_r_package, "hierarchy/a")) + find_root(is_rstudio_project, "hierarchy/a")) }) diff --git a/tests/testthat/test-root.R b/tests/testthat/test-root.R index da39969..061ec8f 100644 --- a/tests/testthat/test-root.R +++ b/tests/testthat/test-root.R @@ -21,13 +21,13 @@ test_that("has_file", { expect_equal(find_root(has_file("DESCRIPTION", "^Package: ", 1), path = path), hierarchy(1L)), expect_equal(find_root(has_file("DESCRIPTION", "^Package: "), path = path), hierarchy(1L)), expect_error(find_root("test-root.R", path = path), - "No root directory found.* file '.*'"), + "No root directory found.* file `.*`"), expect_error(find_root("rprojroot.Rproj", path = path), - "No root directory found.* file '.*'"), + "No root directory found.* file `.*`"), expect_error(find_root(has_file("e", "f"), path = path), - "No root directory found.* file '.*' with contents"), + "No root directory found.* file `.*` with contents"), expect_error(find_root(has_file("e", "f", 1), path = path), - "No root directory found.* file '.*' with contents .* in the first .* lines") + "No root directory found.* file `.*` with contents .* in the first line") ) }) @@ -59,7 +59,31 @@ test_that("has_file_pattern", { expect_error(find_root(has_file_pattern(glob2rx("e"), "f"), path = path), "No root directory found.* with contents"), expect_error(find_root(has_file_pattern(glob2rx("e"), "f", 1), path = path), - "No root directory found.* with contents .* in the first .* lines") + "No root directory found.* with contents .* in the first line") + ) +}) + +test_that("has_dir", { + wd <- normalizePath(getwd(), winslash = "/") + hierarchy <- function(n = 0L) { + do.call(file.path, list(wd, "hierarchy", "a", "b", "c")[seq_len(n + 1L)]) + } + + stop_path <- hierarchy(1L) + path <- hierarchy(4L) + + with_mock( + `rprojroot:::is_root` = function(x) x == stop_path, + expect_equal(find_root(has_dir("a"), path = path), hierarchy(1L)), + expect_equal(find_root(has_dir("b"), path = path), hierarchy(2L)), + expect_equal(find_root_file("c", criterion = has_dir("b"), path = path), + file.path(hierarchy(2L), "c")), + expect_equal(find_root(has_dir("c"), path = path), hierarchy(3L)), + expect_error(find_root(has_dir("d"), path = path), + "No root directory found.* a directory `.*`"), + expect_error(find_root(has_dir("rprojroot.Rproj"), path = path), + "No root directory found.* a directory `.*`"), + TRUE ) }) @@ -80,9 +104,78 @@ test_that("has_dirname", { file.path(hierarchy(3L), "c")), expect_equal(find_root(has_dirname("c"), path = path), hierarchy(4L)), expect_error(find_root(has_dirname("d"), path = path), - "No root directory found.* is '.*'"), + "No root directory found.* is `.*`"), expect_error(find_root(has_dirname("rprojroot.Rproj"), path = path), - "No root directory found.* is '.*'"), + "No root directory found.* is `.*`"), + TRUE + ) +}) + +test_that("concrete criteria", { + wd <- normalizePath(getwd(), winslash = "/") + hierarchy <- function(n = 0L) { + do.call(file.path, list(wd, "hierarchy", "a", "b", "c")[seq_len(n + 1L)]) + } + + # HACK + writeLines(character(), file.path(hierarchy(3L), ".projectile")) + + stop_path <- hierarchy(0L) + path <- hierarchy(4L) + + with_mock( + `rprojroot:::is_root` = function(x) x == stop_path, + expect_equal(find_root(is_rstudio_project, path = path), hierarchy(1L)), + expect_equal(find_root(is_remake_project, path = path), hierarchy(2L)), + expect_equal(find_root(is_projectile_project, path = path), hierarchy(3L)), + TRUE + ) +}) + +test_that("is_svn_root", { + temp_dir <- tempfile("svn") + unzip("vcs/svn.zip", exdir = temp_dir) + wd <- normalizePath(temp_dir, winslash = "/") + + hierarchy <- function(n = 0L) { + do.call(file.path, list(wd, "svn", "a", "b", "c")[seq_len(n + 1L)]) + } + + stop_path <- normalizePath(tempdir(), winslash = "/") + path <- hierarchy(4L) + + with_mock( + `rprojroot:::is_root` = function(x) x == stop_path, + expect_equal(find_root(is_svn_root, path = path), hierarchy(1L)), + expect_equal(find_root(is_vcs_root, path = path), hierarchy(1L)), + expect_error(find_root(is_svn_root, path = hierarchy(0L)), + "No root directory found.* a directory `.*`"), + expect_error(find_root(is_vcs_root, path = hierarchy(0L)), + "No root directory found.* a directory `.*`"), + TRUE + ) +}) + +test_that("is_git_root", { + temp_dir <- tempfile("git") + unzip("vcs/git.zip", exdir = temp_dir) + wd <- normalizePath(temp_dir, winslash = "/") + + hierarchy <- function(n = 0L) { + do.call(file.path, list(wd, "git", "a", "b", "c")[seq_len(n + 1L)]) + } + + stop_path <- normalizePath(tempdir(), winslash = "/") + path <- hierarchy(4L) + + with_mock( + `rprojroot:::is_root` = function(x) x == stop_path, + expect_equal(find_root(is_git_root, path = path), hierarchy(1L)), + expect_equal(find_root(is_vcs_root, path = path), hierarchy(1L)), + expect_error(find_root(is_git_root, path = hierarchy(0L)), + "No root directory found.* a directory `.*`"), + expect_error(find_root(is_vcs_root, path = hierarchy(0L)), + "No root directory found.* a directory `.*`"), TRUE ) }) @@ -90,7 +183,7 @@ test_that("has_dirname", { test_that("finds root", { skip_on_cran() # Checks that search for root actually terminates - expect_error(find_root("/"), "No root directory found.* file '.*'") + expect_error(find_root("/"), "No root directory found.* file `.*`") }) test_that("stops if depth reached", { diff --git a/tests/testthat/test-testthat.R b/tests/testthat/test-testthat.R index 0553586..087c47a 100644 --- a/tests/testthat/test-testthat.R +++ b/tests/testthat/test-testthat.R @@ -1,7 +1,10 @@ context("testthat") test_that("is_testthat", { - expect_match(format(is_testthat), "^.*Directory name is 'testthat' .* subdirectories.*'tests/testthat'.*'testthat'.*$") + expect_match(paste(format(is_testthat), collapse = "\n"), + "^.*directory name is `testthat` .* subdirectories.*`tests/testthat`.*`testthat`.*$") + expect_match(paste(format(is_testthat), collapse = "\n"), + "directory name is `testthat` .* subdirectories.*`tests/testthat`.*`testthat`.*") testthat_path <- normalizePath("package/tests/testthat", winslash = "/") expect_equal(is_testthat$find_file(path = "package"), testthat_path) diff --git a/tests/testthat/vcs/git.zip b/tests/testthat/vcs/git.zip new file mode 100644 index 0000000..1b3ca57 Binary files /dev/null and b/tests/testthat/vcs/git.zip differ diff --git a/tests/testthat/vcs/svn.zip b/tests/testthat/vcs/svn.zip new file mode 100644 index 0000000..0f3fbd7 Binary files /dev/null and b/tests/testthat/vcs/svn.zip differ