├── air.toml ├── .github ├── .gitignore ├── workflows │ ├── pkgdown.yaml │ ├── test-coverage.yaml │ ├── R-CMD-check.yaml │ └── pr-commands.yaml └── CODE_OF_CONDUCT.md ├── revdep ├── README.md ├── failures.md ├── problems.md ├── .gitignore ├── email.yml └── cran.md ├── LICENSE ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── R ├── rappdirs-package.R ├── appdir.R ├── log.R ├── cache.R ├── utils.R └── data.R ├── .Rbuildignore ├── NAMESPACE ├── tests ├── testthat │ ├── test-appdir.R │ ├── _snaps │ │ ├── utils.md │ │ └── appdir.md │ ├── test-log.R │ ├── test-cache.R │ ├── test-utils.R │ └── test-data.R └── testthat.R ├── codecov.yml ├── cran-comments.md ├── src ├── init.c └── win-path.c ├── _pkgdown.yml ├── rappdirs.Rproj ├── NEWS.md ├── LICENSE.md ├── DESCRIPTION ├── man ├── rappdirs-package.Rd ├── app_dir.Rd ├── user_log_dir.Rd ├── user_cache_dir.Rd ├── site_data_dir.Rd └── user_data_dir.Rd ├── README.Rmd └── README.md /air.toml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /revdep/README.md: -------------------------------------------------------------------------------- 1 | # Revdeps 2 | 3 | -------------------------------------------------------------------------------- /revdep/failures.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /revdep/problems.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2025 2 | COPYRIGHT HOLDER: rappdirs authors 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | src/*.*o 3 | .Rproj.user 4 | .Rhistory 5 | docs 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Posit.air-vscode" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /revdep/.gitignore: -------------------------------------------------------------------------------- 1 | checks 2 | library 3 | checks.noindex 4 | library.noindex 5 | data.sqlite 6 | *.html 7 | cloud.noindex 8 | -------------------------------------------------------------------------------- /revdep/email.yml: -------------------------------------------------------------------------------- 1 | release_date: ??? 2 | rel_release_date: ??? 3 | my_news_url: ??? 4 | release_version: ??? 5 | release_details: ??? 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[r]": { 3 | "editor.formatOnSave": true, 4 | "editor.defaultFormatter": "Posit.air-vscode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /R/rappdirs-package.R: -------------------------------------------------------------------------------- 1 | #' @section Main functions: 2 | #' * [user_data_dir()] 3 | #' * [user_config_dir()] 4 | #' * [user_cache_dir()] 5 | #' * [site_data_dir()] 6 | #' * [user_log_dir()] 7 | #' @keywords internal 8 | "_PACKAGE" 9 | -------------------------------------------------------------------------------- /revdep/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 78 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 0 new problems 6 | * We failed to check 0 packages 7 | 8 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^\.travis\.yml$ 4 | ^cran-comments\.md$ 5 | ^codecov\.yml$ 6 | ^\.github$ 7 | ^README\.Rmd$ 8 | ^_pkgdown\.yml$ 9 | ^docs$ 10 | ^pkgdown$ 11 | ^revdep$ 12 | ^CRAN-RELEASE$ 13 | ^LICENSE\.md$ 14 | ^[\.]?air\.toml$ 15 | ^\.vscode$ 16 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(app_dir) 4 | export(site_config_dir) 5 | export(site_data_dir) 6 | export(user_cache_dir) 7 | export(user_config_dir) 8 | export(user_data_dir) 9 | export(user_log_dir) 10 | useDynLib(rappdirs, .registration=TRUE) 11 | -------------------------------------------------------------------------------- /tests/testthat/test-appdir.R: -------------------------------------------------------------------------------- 1 | test_that("appdir works as expected", { 2 | expect_snapshot({ 3 | app <- app_dir("ggplot2", "hadley", os = "mac") 4 | app$cache() 5 | app$log() 6 | app$data() 7 | app$config() 8 | app$site_data() 9 | app$site_config() 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## R CMD check results 2 | 3 | 0 errors | 0 warnings | 1 notes 4 | 5 | * Days since last update: 1 6 | Submitting to fix newly detected LTO issue 7 | 8 | ## revdepcheck results 9 | 10 | We checked 78 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 11 | 12 | * We saw 0 new problems 13 | * We failed to check 0 packages 14 | 15 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/utils.md: -------------------------------------------------------------------------------- 1 | # windows fallbacks work 2 | 3 | Code 4 | win_path_env("foo") 5 | Condition 6 | Error in `win_path_env()`: 7 | ! invalid `type` argument 8 | 9 | # check_version works as expected 10 | 11 | Code 12 | expect_equal(check_version("1", NULL), NULL) 13 | Condition 14 | Warning: 15 | version is ignored when appname is null 16 | Code 17 | expect_equal(check_version("1", "R"), "1") 18 | 19 | -------------------------------------------------------------------------------- /src/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // for NULL 4 | #include 5 | 6 | /* .Call calls */ 7 | extern SEXP win_path_(SEXP); 8 | 9 | static const R_CallMethodDef CallEntries[] = { 10 | {"win_path_", (DL_FUNC) win_path_, 1}, 11 | {NULL, NULL, 0} 12 | }; 13 | 14 | void R_init_rappdirs(DllInfo *dll) 15 | { 16 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 17 | R_useDynamicSymbols(dll, FALSE); 18 | } 19 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://rappdirs.r-lib.org 2 | 3 | template: 4 | package: tidytemplate 5 | bootstrap: 5 6 | 7 | includes: 8 | in_header: | 9 | 10 | 11 | 12 | development: 13 | mode: auto 14 | -------------------------------------------------------------------------------- /rappdirs.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | QuitChildProcessesOnExit: Default 7 | 8 | EnableCodeIndexing: Yes 9 | UseSpacesForTab: Yes 10 | NumSpacesForTab: 2 11 | Encoding: UTF-8 12 | 13 | RnwWeave: knitr 14 | LaTeX: pdfLaTeX 15 | 16 | AutoAppendNewline: Yes 17 | StripTrailingWhitespace: Yes 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /tests/testthat/test-log.R: -------------------------------------------------------------------------------- 1 | test_that("user_cache_dir works as expected", { 2 | expect_equal(user_log_dir("R", os = "mac"), "~/Library/Logs/R") 3 | 4 | withr::local_envvar(XDG_CACHE_HOME = "/cache") 5 | expect_equal(user_log_dir("R", os = "unix"), "/cache/R/log") 6 | expect_equal(user_log_dir("R", os = "unix", opinion = FALSE), "/cache/R") 7 | }) 8 | 9 | test_that("user_cache_dir works with windows simulation", { 10 | skip_on_os("windows") 11 | expect_equal( 12 | user_log_dir("R", os = "win"), 13 | "/Local Settings/Application Data/R/R/Logs" 14 | ) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | # This file is part of the standard setup for testthat. 2 | # It is recommended that you do not modify it. 3 | # 4 | # Where should you do additional test configuration? 5 | # Learn more about the roles of various files in: 6 | # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview 7 | # * https://testthat.r-lib.org/articles/special-files.html 8 | 9 | library(testthat) 10 | library(rappdirs) 11 | 12 | # ensure CRAN settings don't affect tests 13 | Sys.unsetenv("R_USER_DATA_DIR") 14 | Sys.unsetenv("R_USER_CONFIG_DIR") 15 | Sys.unsetenv("R_USER_CACHE_DIR") 16 | 17 | test_check("rappdirs") 18 | -------------------------------------------------------------------------------- /tests/testthat/test-cache.R: -------------------------------------------------------------------------------- 1 | test_that("works on mac and linux", { 2 | withr::local_envvar(XDG_CACHE_HOME = NA) 3 | expect_equal(user_cache_dir("R", os = "unix"), "~/.cache/R") 4 | expect_equal(user_cache_dir("R", os = "mac"), "~/Library/Caches/R") 5 | }) 6 | 7 | test_that("can override with R_USER_CACHE_DIR", { 8 | withr::local_envvar(R_USER_CACHE_DIR = "/test") 9 | expect_equal(user_cache_dir("R", os = "mac"), "/test/R") 10 | }) 11 | test_that("works on windows simulation", { 12 | skip_on_os("windows") 13 | expect_equal( 14 | user_cache_dir("R", os = "win"), 15 | "/Local Settings/Application Data/R/R/Cache" 16 | ) 17 | }) 18 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/appdir.md: -------------------------------------------------------------------------------- 1 | # appdir works as expected 2 | 3 | Code 4 | app <- app_dir("ggplot2", "hadley", os = "mac") 5 | app$cache() 6 | Output 7 | [1] "~/Library/Caches/ggplot2" 8 | Code 9 | app$log() 10 | Output 11 | [1] "~/Library/Logs/ggplot2" 12 | Code 13 | app$data() 14 | Output 15 | [1] "~/Library/Application Support/ggplot2" 16 | Code 17 | app$config() 18 | Output 19 | [1] "~/Library/Application Support/ggplot2" 20 | Code 21 | app$site_data() 22 | Output 23 | [1] "/Library/Application Support/ggplot2" 24 | Code 25 | app$site_config() 26 | Output 27 | [1] "/Library/Application Support/ggplot2" 28 | 29 | -------------------------------------------------------------------------------- /src/win-path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef WIN32 5 | 6 | #include 7 | // SHGetFolderPath documentation: 8 | // http://msdn.microsoft.com/en-us/library/windows/desktop/bb762181.aspx 9 | 10 | SEXP win_path_(SEXP _folder) { 11 | int folder = INTEGER(_folder)[0]; 12 | TCHAR startupFolder[MAX_PATH]; 13 | HRESULT hr = SHGetFolderPath(0, folder, 0, 0, startupFolder); 14 | 15 | if (SUCCEEDED(hr)) { 16 | // Get short path 17 | TCHAR shortPath[MAX_PATH]; 18 | GetShortPathName(startupFolder, shortPath, MAX_PATH); 19 | 20 | return mkString(shortPath); 21 | } 22 | else { 23 | // Return NULL if failed 24 | return R_NilValue; 25 | } 26 | } 27 | 28 | #else 29 | 30 | SEXP win_path_(SEXP folder) { 31 | return R_NilValue; 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # rappdirs (development version) 2 | 3 | # rappdirs 0.3.3 4 | 5 | * rappdirs functions are no longer vectorised; this was an accidental change 6 | in 0.3.2 (#32). 7 | 8 | # rappdirs 0.3.2 9 | 10 | * `user_data_dir()`, `use_cache_dir()` and `use_config_dir()` now respect 11 | `R_USER_DATA_DIR`, `R_USER_CACHE_DIR` and `R_USER_CONFIG_DIR` env vars 12 | (#27). 13 | 14 | * No longer uses methods package. 15 | 16 | # rappdirs 0.3.1 17 | 18 | Minor R CMD check and test fixes. 19 | 20 | # rappdirs 0.3.0 21 | 22 | * first CRAN release 23 | * `xxx_dir()` functions only use version when appname is not null 24 | * docs: basic package docs (?rappdirs) 25 | * docs: clarify primary purpose of os argument in `xxx_dir()` i.e. testing 26 | * fix typo in function name in README.md (app_dirs -> app_dir) 27 | * dev: add travis continuous integration 28 | * dev: add rstudio project 29 | * dev: update to roxygen2 v4.0.1 30 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2025 rappdirs authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/testthat/test-utils.R: -------------------------------------------------------------------------------- 1 | test_that("expand_r_libs_specifiers works as expected", { 2 | expect_equal(expand_r_libs_specifiers("%V"), as.character(getRversion())) 3 | expect_equal(expand_r_libs_specifiers("%%V"), "%V") 4 | expect_equal(expand_r_libs_specifiers(NULL), NULL) 5 | }) 6 | 7 | test_that("file_path drops NULLs", { 8 | expect_equal(file_path("a", NULL, "b"), "a/b") 9 | }) 10 | 11 | test_that("file_path is not vectorised", { 12 | expect_equal(file_path(c("a", "b"), c("c", "d")), "a/b/c/d") 13 | }) 14 | 15 | test_that("windows fallbacks work", { 16 | skip_on_os("windows") 17 | withr::local_envvar(LOCALAPPDATA = NA, PROGRAMDATA = NA) 18 | 19 | expect_equal(win_path_env("roaming"), "") 20 | 21 | expect_equal( 22 | win_path_env("local"), 23 | "/Local Settings/Application Data" 24 | ) 25 | withr::local_envvar(LOCALAPPDATA = "") 26 | expect_equal(win_path_env("local"), "") 27 | 28 | expect_equal(win_path_env("common"), "/Application Data") 29 | withr::local_envvar(PROGRAMDATA = "") 30 | expect_equal(win_path_env("common"), "") 31 | 32 | expect_snapshot(error = TRUE, win_path_env("foo")) 33 | }) 34 | 35 | test_that("check_version works as expected", { 36 | expect_snapshot({ 37 | expect_equal(check_version("1", NULL), NULL) 38 | expect_equal(check_version("1", "R"), "1") 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /R/appdir.R: -------------------------------------------------------------------------------- 1 | #' Record app information in a convenient object 2 | #' 3 | #' @description 4 | #' Has methods: 5 | #' * `$cache()` 6 | #' * `$log()` 7 | #' * `$data()` 8 | #' * `$config()` 9 | #' * `$site_data()` 10 | #' * `$site_config()` 11 | #' 12 | #' @inheritParams user_data_dir 13 | #' @keywords internal 14 | #' @export 15 | #' @examples 16 | #' ggplot2_app <- app_dir("ggplot2", "hadley") 17 | #' ggplot2_app$cache() 18 | #' ggplot2_app$log() 19 | #' ggplot2_app$data() 20 | #' ggplot2_app$config() 21 | #' ggplot2_app$site_config() 22 | #' ggplot2_app$site_data() 23 | app_dir <- function( 24 | appname = NULL, 25 | appauthor = appname, 26 | version = NULL, 27 | expand = TRUE, 28 | os = NULL 29 | ) { 30 | os <- check_os(os) 31 | list( 32 | cache = function(opinion = TRUE) 33 | user_cache_dir(appname, appauthor, version, opinion, expand, os), 34 | log = function(opinion = TRUE) 35 | user_log_dir(appname, appauthor, version, opinion, expand, os), 36 | data = function(roaming = FALSE) 37 | user_data_dir(appname, appauthor, version, roaming, expand, os), 38 | config = function(roaming = FALSE) 39 | user_config_dir(appname, appauthor, version, roaming, expand, os), 40 | site_data = function(multipath = FALSE) 41 | site_data_dir(appname, appauthor, version, multipath, expand, os), 42 | site_config = function(multipath = FALSE) 43 | site_config_dir(appname, appauthor, version, multipath, expand, os), 44 | os = os 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | release: 8 | types: [published] 9 | workflow_dispatch: 10 | 11 | name: pkgdown.yaml 12 | 13 | permissions: read-all 14 | 15 | jobs: 16 | pkgdown: 17 | runs-on: ubuntu-latest 18 | # Only restrict concurrency for non-PR jobs 19 | concurrency: 20 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 21 | env: 22 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 23 | permissions: 24 | contents: write 25 | steps: 26 | - uses: actions/checkout@v4 27 | 28 | - uses: r-lib/actions/setup-pandoc@v2 29 | 30 | - uses: r-lib/actions/setup-r@v2 31 | with: 32 | use-public-rspm: true 33 | 34 | - uses: r-lib/actions/setup-r-dependencies@v2 35 | with: 36 | extra-packages: any::pkgdown, local::. 37 | needs: website 38 | 39 | - name: Build site 40 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 41 | shell: Rscript {0} 42 | 43 | - name: Deploy to GitHub pages 🚀 44 | if: github.event_name != 'pull_request' 45 | uses: JamesIves/github-pages-deploy-action@v4.5.0 46 | with: 47 | clean: false 48 | branch: gh-pages 49 | folder: docs 50 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Type: Package 2 | Package: rappdirs 3 | Title: Application Directories: Determine Where to Save Data, Caches, and 4 | Logs 5 | Version: 0.3.3.9000 6 | Authors@R: c( 7 | person("Hadley", "Wickham", , "hadley@posit.co", role = c("trl", "cre", "cph")), 8 | person("Sridhar", "Ratnakumar", role = "aut"), 9 | person("Trent", "Mick", role = "aut"), 10 | person("ActiveState", role = "cph", 11 | comment = "R/appdir.r, R/cache.r, R/data.r, R/log.r translated from appdirs"), 12 | person("Eddy", "Petrisor", role = "ctb"), 13 | person("Trevor", "Davis", role = c("trl", "aut"), 14 | comment = c(ORCID = "0000-0001-6341-4639")), 15 | person("Gabor", "Csardi", role = "ctb"), 16 | person("Gregory", "Jefferis", role = "ctb"), 17 | person("Posit Software, PBC", role = c("cph", "fnd"), 18 | comment = c(ROR = "03wc8by49")) 19 | ) 20 | Description: An easy way to determine which directories on the users 21 | computer you should use to save data, caches and logs. A port of 22 | Python's 'Appdirs' () to R. 23 | License: MIT + file LICENSE 24 | URL: https://rappdirs.r-lib.org, https://github.com/r-lib/rappdirs 25 | BugReports: https://github.com/r-lib/rappdirs/issues 26 | Depends: 27 | R (>= 4.1) 28 | Suggests: 29 | covr, 30 | roxygen2, 31 | testthat (>= 3.2.0), 32 | withr 33 | Config/Needs/website: tidyverse/tidytemplate 34 | Config/testthat/edition: 3 35 | Config/usethis/last-upkeep: 2025-05-05 36 | Copyright: Original python appdirs module copyright (c) 2010 ActiveState 37 | Software Inc. R port copyright Hadley Wickham, Posit, PBC. See file 38 | LICENSE for details. 39 | Encoding: UTF-8 40 | Roxygen: list(markdown = TRUE) 41 | RoxygenNote: 7.2.3 42 | -------------------------------------------------------------------------------- /man/rappdirs-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rappdirs-package.r 3 | \docType{package} 4 | \name{rappdirs-package} 5 | \alias{rappdirs} 6 | \alias{rappdirs-package} 7 | \title{rappdirs: Application Directories: Determine Where to Save Data, Caches, and Logs} 8 | \description{ 9 | An easy way to determine which directories on the users computer you should use to save data, caches and logs. A port of Python's 'Appdirs' (\url{https://github.com/ActiveState/appdirs}) to R. 10 | } 11 | \section{Main functions}{ 12 | 13 | \itemize{ 14 | \item \code{\link[=user_data_dir]{user_data_dir()}} 15 | \item \code{\link[=user_config_dir]{user_config_dir()}} 16 | \item \code{\link[=user_cache_dir]{user_cache_dir()}} 17 | \item \code{\link[=site_data_dir]{site_data_dir()}} 18 | \item \code{\link[=user_log_dir]{user_log_dir()}} 19 | } 20 | } 21 | 22 | \seealso{ 23 | Useful links: 24 | \itemize{ 25 | \item \url{https://rappdirs.r-lib.org} 26 | \item \url{https://github.com/r-lib/rappdirs} 27 | \item Report bugs at \url{https://github.com/r-lib/rappdirs/issues} 28 | } 29 | 30 | } 31 | \author{ 32 | \strong{Maintainer}: Hadley Wickham \email{hadley@rstudio.com} [translator, copyright holder] 33 | 34 | Authors: 35 | \itemize{ 36 | \item Sridhar Ratnakumar 37 | \item Trent Mick 38 | \item Trevor Davis [translator] 39 | } 40 | 41 | Other contributors: 42 | \itemize{ 43 | \item RStudio [copyright holder] 44 | \item ActiveState (R/appdir.r, R/cache.r, R/data.r, R/log.r translated from appdirs) [copyright holder] 45 | \item Eddy Petrisor [contributor] 46 | \item Gabor Csardi [contributor] 47 | \item Gregory Jefferis [contributor] 48 | \item Posit Software, PBC [copyright holder, funder] 49 | } 50 | 51 | } 52 | \keyword{internal} 53 | -------------------------------------------------------------------------------- /man/app_dir.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/appdir.r 3 | \name{app_dir} 4 | \alias{app_dir} 5 | \title{Record app information in a convenient object} 6 | \usage{ 7 | app_dir( 8 | appname = NULL, 9 | appauthor = appname, 10 | version = NULL, 11 | expand = TRUE, 12 | os = NULL 13 | ) 14 | } 15 | \arguments{ 16 | \item{appname}{is the name of application. If NULL, just the system 17 | directory is returned.} 18 | 19 | \item{appauthor}{(only required and used on Windows) is the name of the 20 | appauthor or distributing body for this application. Typically 21 | it is the owning company name. This falls back to appname.} 22 | 23 | \item{version}{is an optional version path element to append to the 24 | path. You might want to use this if you want multiple versions 25 | of your app to be able to run independently. If used, this 26 | would typically be \code{"."}. Only applied when appname 27 | is not NULL.} 28 | 29 | \item{expand}{If TRUE (the default) will expand the \code{R_LIBS} specifiers with their equivalents. 30 | See \code{\link[=R_LIBS]{R_LIBS()}} for list of all possibly specifiers.} 31 | 32 | \item{os}{Operating system whose conventions are used to construct the 33 | requested directory. Possible values are "win", "mac", "unix". If \code{NULL} 34 | (the default) then the current OS will be used.} 35 | } 36 | \description{ 37 | Has methods: 38 | \itemize{ 39 | \item \verb{$cache()} 40 | \item \verb{$log()} 41 | \item \verb{$data()} 42 | \item \verb{$config()} 43 | \item \verb{$site_data()} 44 | \item \verb{$site_config()} 45 | } 46 | } 47 | \examples{ 48 | ggplot2_app <- app_dir("ggplot2", "hadley") 49 | ggplot2_app$cache() 50 | ggplot2_app$log() 51 | ggplot2_app$data() 52 | ggplot2_app$config() 53 | ggplot2_app$site_config() 54 | ggplot2_app$site_data() 55 | } 56 | \keyword{internal} 57 | -------------------------------------------------------------------------------- /R/log.R: -------------------------------------------------------------------------------- 1 | #' Path to user log directory 2 | #' 3 | #' Typical user cache directories are: 4 | #' 5 | #' \itemize{ 6 | #' \item Mac OS X: \file{~/Library/Logs/} 7 | #' \item Unix: \file{~/.cache//log}, or under 8 | #' \env{$XDG_CACHE_HOME} if defined 9 | #' \item Win XP: \file{C:\\Documents and Settings\\\\Local Settings\\Application Data\\\\\\Logs} 10 | #' \item Vista: 11 | #' \file{C:\\Users\\\\AppData\\Local\\\\\\Logs} 12 | #' } 13 | #' 14 | #' On Windows the only suggestion in the MSDN docs is that local settings 15 | #' go in the `CSIDL_LOCAL_APPDATA` directory. 16 | #' 17 | #' @section Opinion: 18 | #' This function appends \file{Logs} to the `CSIDL_LOCAL_APPDATA` 19 | #' value for Windows and appends \file{log} to the user cache dir for Unix. 20 | #' This can be disabled with the `opinion = FALSE` option. 21 | #' 22 | #' @inheritParams user_data_dir 23 | #' @param opinion (logical) can be `FALSE` to disable the appending of 24 | #' \file{Logs} to the base app data dir for Windows, and \file{log} to the 25 | #' base cache dir for Unix. See discussion below. 26 | #' @examples 27 | #' user_log_dir() 28 | #' @export 29 | user_log_dir <- function( 30 | appname = NULL, 31 | appauthor = appname, 32 | version = NULL, 33 | opinion = TRUE, 34 | expand = TRUE, 35 | os = NULL 36 | ) { 37 | version <- check_version(version, appname, expand) 38 | 39 | switch( 40 | check_os(os), 41 | win = file_path( 42 | win_path("local"), 43 | appauthor, 44 | appname, 45 | version, 46 | if (opinion) "Logs" 47 | ), 48 | mac = file_path("~/Library/Logs", appname, version), 49 | unix = file_path( 50 | Sys.getenv("XDG_CACHE_HOME", "~/.cache"), 51 | appname, 52 | version, 53 | if (opinion) "log" 54 | ) 55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /R/cache.R: -------------------------------------------------------------------------------- 1 | #' Path to user cache directory 2 | #' 3 | #' @description 4 | #' This functions uses `R_USER_CACHE_DIR` if set. Otherwise, they follow 5 | #' platform conventions. Typical user cache directories are: 6 | #' 7 | #' * Mac OS X: `~/Library/Caches/` 8 | #' * Linux: `~/.cache/` 9 | #' * Win XP: `C:\\Documents and Settings\\\\Local Settings\\Application Data\\\\\\Cache` 10 | #' * Vista: `C:\\Users\\\\AppData\\Local\\\\\\Cache` 11 | #' 12 | #' @section Opinion: 13 | #' On Windows the only suggestion in the MSDN docs is that local settings go 14 | #' in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the 15 | #' non-roaming app data dir (i.e. [user_data_dir()]). But apps typically put 16 | #' cache data somewhere *under* this directory so `user_cache_dir()` appends 17 | #' `Cache` to the `CSIDL_LOCAL_APPDATA` value, unless `opinion = FALSE`. 18 | #' 19 | #' @inheritParams user_data_dir 20 | #' @param opinion (logical) Use `FALSE` to disable the appending of 21 | #' `Cache` on Windows. See discussion below. 22 | #' @seealso [tempdir()] for a non-persistent temporary directory. 23 | #' @export 24 | #' @examples 25 | #' user_cache_dir("rappdirs") 26 | user_cache_dir <- function( 27 | appname = NULL, 28 | appauthor = appname, 29 | version = NULL, 30 | opinion = TRUE, 31 | expand = TRUE, 32 | os = NULL 33 | ) { 34 | version <- check_version(version, appname, expand) 35 | 36 | base <- base_path( 37 | os, 38 | "CACHE", 39 | win = win_path("local"), 40 | mac = "~/Library/Caches", 41 | unix = Sys.getenv("XDG_CACHE_HOME", "~/.cache") 42 | ) 43 | 44 | switch( 45 | check_os(os), 46 | win = file_path(base, appauthor, appname, version, if (opinion) "Cache"), 47 | mac = file_path(base, appname, version), 48 | unix = file_path(base, appname, version) 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | 8 | name: test-coverage.yaml 9 | 10 | permissions: read-all 11 | 12 | jobs: 13 | test-coverage: 14 | runs-on: ubuntu-latest 15 | env: 16 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - uses: r-lib/actions/setup-r@v2 22 | with: 23 | use-public-rspm: true 24 | 25 | - uses: r-lib/actions/setup-r-dependencies@v2 26 | with: 27 | extra-packages: any::covr, any::xml2 28 | needs: coverage 29 | 30 | - name: Test coverage 31 | run: | 32 | cov <- covr::package_coverage( 33 | quiet = FALSE, 34 | clean = FALSE, 35 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 36 | ) 37 | print(cov) 38 | covr::to_cobertura(cov) 39 | shell: Rscript {0} 40 | 41 | - uses: codecov/codecov-action@v5 42 | with: 43 | # Fail if error if not on PR, or if on PR and token is given 44 | fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }} 45 | files: ./cobertura.xml 46 | plugins: noop 47 | disable_search: true 48 | token: ${{ secrets.CODECOV_TOKEN }} 49 | 50 | - name: Show testthat output 51 | if: always() 52 | run: | 53 | ## -------------------------------------------------------------------- 54 | find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true 55 | shell: bash 56 | 57 | - name: Upload test results 58 | if: failure() 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: coverage-test-failures 62 | path: ${{ runner.temp }}/package 63 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | # 4 | # NOTE: This workflow is overkill for most R packages and 5 | # check-standard.yaml is likely a better choice. 6 | # usethis::use_github_action("check-standard") will install it. 7 | on: 8 | push: 9 | branches: [main, master] 10 | pull_request: 11 | 12 | name: R-CMD-check.yaml 13 | 14 | permissions: read-all 15 | 16 | jobs: 17 | R-CMD-check: 18 | runs-on: ${{ matrix.config.os }} 19 | 20 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | config: 26 | - {os: macos-latest, r: 'release'} 27 | 28 | - {os: windows-latest, r: 'release'} 29 | # use 4.0 or 4.1 to check with rtools40's older compiler 30 | - {os: windows-latest, r: 'oldrel-4'} 31 | 32 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 33 | - {os: ubuntu-latest, r: 'release'} 34 | - {os: ubuntu-latest, r: 'oldrel-1'} 35 | - {os: ubuntu-latest, r: 'oldrel-2'} 36 | - {os: ubuntu-latest, r: 'oldrel-3'} 37 | - {os: ubuntu-latest, r: 'oldrel-4'} 38 | 39 | env: 40 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 41 | R_KEEP_PKG_SOURCE: yes 42 | 43 | steps: 44 | - uses: actions/checkout@v4 45 | 46 | - uses: r-lib/actions/setup-pandoc@v2 47 | 48 | - uses: r-lib/actions/setup-r@v2 49 | with: 50 | r-version: ${{ matrix.config.r }} 51 | http-user-agent: ${{ matrix.config.http-user-agent }} 52 | use-public-rspm: true 53 | 54 | - uses: r-lib/actions/setup-r-dependencies@v2 55 | with: 56 | extra-packages: any::rcmdcheck 57 | needs: check 58 | 59 | - uses: r-lib/actions/check-r-package@v2 60 | with: 61 | upload-snapshots: true 62 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 63 | -------------------------------------------------------------------------------- /man/user_log_dir.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/log.r 3 | \name{user_log_dir} 4 | \alias{user_log_dir} 5 | \title{Path to user log directory} 6 | \usage{ 7 | user_log_dir( 8 | appname = NULL, 9 | appauthor = appname, 10 | version = NULL, 11 | opinion = TRUE, 12 | expand = TRUE, 13 | os = NULL 14 | ) 15 | } 16 | \arguments{ 17 | \item{appname}{is the name of application. If NULL, just the system 18 | directory is returned.} 19 | 20 | \item{appauthor}{(only required and used on Windows) is the name of the 21 | appauthor or distributing body for this application. Typically 22 | it is the owning company name. This falls back to appname.} 23 | 24 | \item{version}{is an optional version path element to append to the 25 | path. You might want to use this if you want multiple versions 26 | of your app to be able to run independently. If used, this 27 | would typically be \code{"."}. Only applied when appname 28 | is not NULL.} 29 | 30 | \item{opinion}{(logical) can be \code{FALSE} to disable the appending of 31 | \file{Logs} to the base app data dir for Windows, and \file{log} to the 32 | base cache dir for Unix. See discussion below.} 33 | 34 | \item{expand}{If TRUE (the default) will expand the \code{R_LIBS} specifiers with their equivalents. 35 | See \code{\link[=R_LIBS]{R_LIBS()}} for list of all possibly specifiers.} 36 | 37 | \item{os}{Operating system whose conventions are used to construct the 38 | requested directory. Possible values are "win", "mac", "unix". If \code{NULL} 39 | (the default) then the current OS will be used.} 40 | } 41 | \description{ 42 | Typical user cache directories are: 43 | } 44 | \details{ 45 | \itemize{ 46 | \item Mac OS X: \file{~/Library/Logs/} 47 | \item Unix: \file{~/.cache//log}, or under 48 | \env{$XDG_CACHE_HOME} if defined 49 | \item Win XP: \file{C:\\Documents and Settings\\\\Local Settings\\Application Data\\\\\\Logs} 50 | \item Vista: 51 | \file{C:\\Users\\\\AppData\\Local\\\\\\Logs} 52 | } 53 | 54 | On Windows the only suggestion in the MSDN docs is that local settings 55 | go in the \code{CSIDL_LOCAL_APPDATA} directory. 56 | } 57 | \section{Opinion}{ 58 | 59 | This function appends \file{Logs} to the \code{CSIDL_LOCAL_APPDATA} 60 | value for Windows and appends \file{log} to the user cache dir for Unix. 61 | This can be disabled with the \code{opinion = FALSE} option. 62 | } 63 | 64 | \examples{ 65 | user_log_dir() 66 | } 67 | -------------------------------------------------------------------------------- /man/user_cache_dir.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cache.r 3 | \name{user_cache_dir} 4 | \alias{user_cache_dir} 5 | \title{Path to user cache directory} 6 | \usage{ 7 | user_cache_dir( 8 | appname = NULL, 9 | appauthor = appname, 10 | version = NULL, 11 | opinion = TRUE, 12 | expand = TRUE, 13 | os = NULL 14 | ) 15 | } 16 | \arguments{ 17 | \item{appname}{is the name of application. If NULL, just the system 18 | directory is returned.} 19 | 20 | \item{appauthor}{(only required and used on Windows) is the name of the 21 | appauthor or distributing body for this application. Typically 22 | it is the owning company name. This falls back to appname.} 23 | 24 | \item{version}{is an optional version path element to append to the 25 | path. You might want to use this if you want multiple versions 26 | of your app to be able to run independently. If used, this 27 | would typically be \code{"."}. Only applied when appname 28 | is not NULL.} 29 | 30 | \item{opinion}{(logical) Use \code{FALSE} to disable the appending of 31 | \code{Cache} on Windows. See discussion below.} 32 | 33 | \item{expand}{If TRUE (the default) will expand the \code{R_LIBS} specifiers with their equivalents. 34 | See \code{\link[=R_LIBS]{R_LIBS()}} for list of all possibly specifiers.} 35 | 36 | \item{os}{Operating system whose conventions are used to construct the 37 | requested directory. Possible values are "win", "mac", "unix". If \code{NULL} 38 | (the default) then the current OS will be used.} 39 | } 40 | \description{ 41 | This functions uses \code{R_USER_CACHE_DIR} if set. Otherwise, they follow 42 | platform conventions. Typical user cache directories are: 43 | \itemize{ 44 | \item Mac OS X: \verb{~/Library/Caches/} 45 | \item Linux: \verb{~/.cache/} 46 | \item Win XP: \verb{C:\\\\Documents and Settings\\\\\\\\Local Settings\\\\Application Data\\\\\\\\\\\\Cache} 47 | \item Vista: \verb{C:\\\\Users\\\\\\\\AppData\\\\Local\\\\\\\\\\\\Cache} 48 | } 49 | } 50 | \section{Opinion}{ 51 | 52 | On Windows the only suggestion in the MSDN docs is that local settings go 53 | in the \code{CSIDL_LOCAL_APPDATA} directory. This is identical to the 54 | non-roaming app data dir (i.e. \code{\link[=user_data_dir]{user_data_dir()}}). But apps typically put 55 | cache data somewhere \emph{under} this directory so \code{user_cache_dir()} appends 56 | \code{Cache} to the \code{CSIDL_LOCAL_APPDATA} value, unless \code{opinion = FALSE}. 57 | } 58 | 59 | \examples{ 60 | user_cache_dir("rappdirs") 61 | } 62 | \seealso{ 63 | \code{\link[=tempdir]{tempdir()}} for a non-persistent temporary directory. 64 | } 65 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r} 8 | #| include: false 9 | knitr::opts_chunk$set( 10 | collapse = TRUE, 11 | comment = "#>", 12 | fig.path = "man/figures/README-", 13 | out.width = "100%" 14 | ) 15 | ``` 16 | 17 | # rappdirs 18 | 19 | 20 | [![R-CMD-check](https://github.com/r-lib/rappdirs/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/rappdirs/actions/workflows/R-CMD-check.yaml) 21 | [![Codecov test coverage](https://codecov.io/gh/r-lib/rappdirs/graph/badge.svg)](https://app.codecov.io/gh/r-lib/rappdirs) 22 | 23 | 24 | `rappdirs` is a port of [appdirs](https://github.com/ActiveState/appdirs) to R. 25 | It lets you find the appropriate directory to save caches, logs, and data, on Linux, Mac, and Windows. 26 | It allows you to store files that need to shared across R sessions in a way that aligns with the [CRAN policies](https://cran.r-project.org/web/packages/policies.html). 27 | 28 | ## Motivation 29 | 30 | What directory should your app use for storing user data? 31 | If running on Mac OS X, you should use: 32 | 33 | ~/Library/Application Support/ 34 | 35 | If on Windows (at least English Win XP) that should be: 36 | 37 | C:\Documents and Settings\\Application Data\Local Settings\\ 38 | 39 | or possibly: 40 | 41 | C:\Documents and Settings\\Application Data\\ 42 | 43 | for [roaming profiles](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-vista/cc766489(v=ws.10)) but that is another story. 44 | 45 | On Linux (and other Unices) the dir, according to the [XDG spec](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) (and subject to some interpretation), is either: 46 | 47 | ~/.config/ 48 | 49 | or possibly: 50 | 51 | ~/.local/share/ 52 | 53 | ## Installation 54 | 55 | Stable version: 56 | 57 | ```r 58 | install.packages("rappdirs") 59 | ``` 60 | 61 | Development version: 62 | 63 | ```r 64 | pak::pak("r-lib/rappdirs") 65 | ``` 66 | 67 | ## Usage 68 | 69 | This kind of thing is what rappdirs is for. 70 | rappdirs will help you choose an appropriate: 71 | 72 | - user data dir (`user_data_dir()`) 73 | - user config dir (`user_config_dir()`) 74 | - user cache dir (`user_cache_dir()`) 75 | - site data dir (`site_data_dir()`) 76 | - user log dir (`user_log_dir()`) 77 | 78 | For example, on Mac: 79 | 80 | ```{r} 81 | library(rappdirs) 82 | appname <- "SuperApp" 83 | appauthor <- "Acme" 84 | user_config_dir(appname, appauthor) 85 | user_data_dir(appname, appauthor) 86 | site_data_dir(appname, appauthor) 87 | user_cache_dir(appname, appauthor) 88 | user_log_dir(appname, appauthor) 89 | ``` 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # rappdirs 5 | 6 | 7 | 8 | [![R-CMD-check](https://github.com/r-lib/rappdirs/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/rappdirs/actions/workflows/R-CMD-check.yaml) 9 | [![Codecov test 10 | coverage](https://codecov.io/gh/r-lib/rappdirs/graph/badge.svg)](https://app.codecov.io/gh/r-lib/rappdirs) 11 | 12 | 13 | `rappdirs` is a port of 14 | [appdirs](https://github.com/ActiveState/appdirs) to R. It lets you find 15 | the appropriate directory to save caches, logs, and data, on Linux, Mac, 16 | and Windows. It allows you to store files that need to shared across R 17 | sessions in a way that aligns with the [CRAN 18 | policies](https://cran.r-project.org/web/packages/policies.html). 19 | 20 | ## Motivation 21 | 22 | What directory should your app use for storing user data? If running on 23 | Mac OS X, you should use: 24 | 25 | ~/Library/Application Support/ 26 | 27 | If on Windows (at least English Win XP) that should be: 28 | 29 | C:\Documents and Settings\\Application Data\Local Settings\\ 30 | 31 | or possibly: 32 | 33 | C:\Documents and Settings\\Application Data\\ 34 | 35 | for [roaming 36 | profiles](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-vista/cc766489(v=ws.10)) 37 | but that is another story. 38 | 39 | On Linux (and other Unices) the dir, according to the [XDG 40 | spec](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) 41 | (and subject to some interpretation), is either: 42 | 43 | ~/.config/ 44 | 45 | or possibly: 46 | 47 | ~/.local/share/ 48 | 49 | ## Installation 50 | 51 | Stable version: 52 | 53 | ``` r 54 | install.packages("rappdirs") 55 | ``` 56 | 57 | Development version: 58 | 59 | ``` r 60 | pak::pak("r-lib/rappdirs") 61 | ``` 62 | 63 | ## Usage 64 | 65 | This kind of thing is what rappdirs is for. rappdirs will help you 66 | choose an appropriate: 67 | 68 | - user data dir (`user_data_dir()`) 69 | - user config dir (`user_config_dir()`) 70 | - user cache dir (`user_cache_dir()`) 71 | - site data dir (`site_data_dir()`) 72 | - user log dir (`user_log_dir()`) 73 | 74 | For example, on Mac: 75 | 76 | ``` r 77 | library(rappdirs) 78 | appname <- "SuperApp" 79 | appauthor <- "Acme" 80 | user_config_dir(appname, appauthor) 81 | #> [1] "~/Library/Application Support/SuperApp" 82 | user_data_dir(appname, appauthor) 83 | #> [1] "~/Library/Application Support/SuperApp" 84 | site_data_dir(appname, appauthor) 85 | #> [1] "/Library/Application Support/SuperApp" 86 | user_cache_dir(appname, appauthor) 87 | #> [1] "~/Library/Caches/SuperApp" 88 | user_log_dir(appname, appauthor) 89 | #> [1] "~/Library/Logs/SuperApp" 90 | ``` 91 | -------------------------------------------------------------------------------- /.github/workflows/pr-commands.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | name: pr-commands.yaml 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | document: 13 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} 14 | name: document 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | permissions: 19 | contents: write 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - uses: r-lib/actions/pr-fetch@v2 24 | with: 25 | repo-token: ${{ secrets.GITHUB_TOKEN }} 26 | 27 | - uses: r-lib/actions/setup-r@v2 28 | with: 29 | use-public-rspm: true 30 | 31 | - uses: r-lib/actions/setup-r-dependencies@v2 32 | with: 33 | extra-packages: any::roxygen2 34 | needs: pr-document 35 | 36 | - name: Document 37 | run: roxygen2::roxygenise() 38 | shell: Rscript {0} 39 | 40 | - name: commit 41 | run: | 42 | git config --local user.name "$GITHUB_ACTOR" 43 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 44 | git add man/\* NAMESPACE 45 | git commit -m 'Document' 46 | 47 | - uses: r-lib/actions/pr-push@v2 48 | with: 49 | repo-token: ${{ secrets.GITHUB_TOKEN }} 50 | 51 | style: 52 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }} 53 | name: style 54 | runs-on: ubuntu-latest 55 | env: 56 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 57 | permissions: 58 | contents: write 59 | steps: 60 | - uses: actions/checkout@v4 61 | 62 | - uses: r-lib/actions/pr-fetch@v2 63 | with: 64 | repo-token: ${{ secrets.GITHUB_TOKEN }} 65 | 66 | - uses: r-lib/actions/setup-r@v2 67 | 68 | - name: Install dependencies 69 | run: install.packages("styler") 70 | shell: Rscript {0} 71 | 72 | - name: Style 73 | run: styler::style_pkg() 74 | shell: Rscript {0} 75 | 76 | - name: commit 77 | run: | 78 | git config --local user.name "$GITHUB_ACTOR" 79 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 80 | git add \*.R 81 | git commit -m 'Style' 82 | 83 | - uses: r-lib/actions/pr-push@v2 84 | with: 85 | repo-token: ${{ secrets.GITHUB_TOKEN }} 86 | -------------------------------------------------------------------------------- /man/site_data_dir.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.r 3 | \name{site_data_dir} 4 | \alias{site_data_dir} 5 | \alias{site_config_dir} 6 | \title{Path to shared data/config directories} 7 | \usage{ 8 | site_data_dir( 9 | appname = NULL, 10 | appauthor = appname, 11 | version = NULL, 12 | multipath = FALSE, 13 | expand = TRUE, 14 | os = NULL 15 | ) 16 | 17 | site_config_dir( 18 | appname = NULL, 19 | appauthor = appname, 20 | version = NULL, 21 | multipath = FALSE, 22 | expand = TRUE, 23 | os = NULL 24 | ) 25 | } 26 | \arguments{ 27 | \item{appname}{is the name of application. If NULL, just the system 28 | directory is returned.} 29 | 30 | \item{appauthor}{(only required and used on Windows) is the name of the 31 | appauthor or distributing body for this application. Typically 32 | it is the owning company name. This falls back to appname.} 33 | 34 | \item{version}{is an optional version path element to append to the 35 | path. You might want to use this if you want multiple versions 36 | of your app to be able to run independently. If used, this 37 | would typically be \code{"."}. Only applied when appname 38 | is not NULL.} 39 | 40 | \item{multipath}{is an optional parameter only applicable to *nix 41 | which indicates that the entire list of data dirs should be returned 42 | By default, the first directory is returned} 43 | 44 | \item{expand}{If TRUE (the default) will expand the \code{R_LIBS} specifiers with their equivalents. 45 | See \code{\link[=R_LIBS]{R_LIBS()}} for list of all possibly specifiers.} 46 | 47 | \item{os}{Operating system whose conventions are used to construct the 48 | requested directory. Possible values are "win", "mac", "unix". If \code{NULL} 49 | (the default) then the current OS will be used.} 50 | } 51 | \description{ 52 | \code{site_data_dir} returns full path to the user-shared data dir for this application. 53 | \code{site_config_dir} returns full path to the user-specific configuration directory for this application 54 | which returns the same path as site data directory in Windows and Mac but a different one for Unix. 55 | Typical user-shared data directories are: 56 | } 57 | \details{ 58 | \itemize{ 59 | \item Mac OS X: \verb{/Library/Application Support/} 60 | \item Unix: \verb{/usr/local/share:/usr/share/} 61 | \item Win XP: \verb{C:\\\\Documents and Settings\\\\All Users\\\\Application Data\\\\\\\\} 62 | \item Vista: (Fail! \verb{C:\\\\ProgramData} is a hidden \emph{system} directory on Vista.) 63 | \item Win 7: \verb{C:\\\\ProgramData\\\\\\\\}. Hidden, but writeable on Win 7. 64 | } 65 | 66 | Unix also specifies a separate location for user-shared configuration data in \env{$XDG_CONFIG_DIRS}. 67 | \itemize{ 68 | \item Unix: \verb{/etc/xdg/}, in \env{$XDG_CONFIG_HOME} if defined 69 | } 70 | 71 | For Unix, this returns the first default. Set the \code{multipath=TRUE} to guarantee returning all directories. 72 | } 73 | \section{Warning}{ 74 | 75 | Do not use this on Windows. See the note above for why. 76 | } 77 | 78 | -------------------------------------------------------------------------------- /man/user_data_dir.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.r 3 | \name{user_data_dir} 4 | \alias{user_data_dir} 5 | \alias{user_config_dir} 6 | \title{Path to user config/data directories} 7 | \usage{ 8 | user_data_dir( 9 | appname = NULL, 10 | appauthor = appname, 11 | version = NULL, 12 | roaming = FALSE, 13 | expand = TRUE, 14 | os = NULL 15 | ) 16 | 17 | user_config_dir( 18 | appname = NULL, 19 | appauthor = appname, 20 | version = NULL, 21 | roaming = TRUE, 22 | expand = TRUE, 23 | os = NULL 24 | ) 25 | } 26 | \arguments{ 27 | \item{appname}{is the name of application. If NULL, just the system 28 | directory is returned.} 29 | 30 | \item{appauthor}{(only required and used on Windows) is the name of the 31 | appauthor or distributing body for this application. Typically 32 | it is the owning company name. This falls back to appname.} 33 | 34 | \item{version}{is an optional version path element to append to the 35 | path. You might want to use this if you want multiple versions 36 | of your app to be able to run independently. If used, this 37 | would typically be \code{"."}. Only applied when appname 38 | is not NULL.} 39 | 40 | \item{roaming}{(logical, default \code{FALSE}) can be set \code{TRUE} to 41 | use the Windows roaming appdata directory. That means that for users on 42 | a Windows network setup for roaming profiles, this user data will be 43 | sync'd on login. See 44 | } 64 | \item Win XP (not roaming): \verb{C:\\\\Documents and Settings\\\\\\\\Data\\\\\\\\} 65 | \item Win XP (roaming): \verb{C:\\\\Documents and Settings\\\\\\\\Local Settings\\\\Data\\\\\\\\} 66 | \item Win 7 (not roaming): \verb{C:\\\\Users\\\\\\\\AppData\\\\Local\\\\\\\\} 67 | \item Win 7 (roaming): \verb{C:\\\\Users\\\\\\\\AppData\\\\Roaming\\\\\\\\} 68 | } 69 | 70 | Only Linux makes the distinction between config and data: 71 | \itemize{ 72 | \item Data: \verb{~/.local/share/} 73 | \item Config: \verb{~/.config/} 74 | } 75 | } 76 | \examples{ 77 | user_data_dir("rappdirs") 78 | 79 | user_config_dir("rappdirs", roaming = TRUE, os = "win") 80 | user_config_dir("rappdirs", roaming = FALSE, os = "win") 81 | user_config_dir("rappdirs", os = "unix") 82 | user_config_dir("rappdirs", os = "mac") 83 | user_config_dir("rappdirs", version = "\%p-platform/\%v") 84 | } 85 | -------------------------------------------------------------------------------- /tests/testthat/test-data.R: -------------------------------------------------------------------------------- 1 | test_that("default paths work on mac", { 2 | expect_equal( 3 | user_data_dir("R", os = "mac"), 4 | "~/Library/Application Support/R" 5 | ) 6 | expect_equal( 7 | user_config_dir("R", os = "mac"), 8 | "~/Library/Application Support/R" 9 | ) 10 | expect_equal(site_data_dir("R", os = "mac"), "/Library/Application Support/R") 11 | expect_equal( 12 | site_config_dir("R", os = "mac"), 13 | "/Library/Application Support/R" 14 | ) 15 | }) 16 | 17 | test_that("default paths work on linux", { 18 | withr::local_envvar( 19 | XDG_DATA_HOME = NA, 20 | XDG_CONFIG_HOME = NA, 21 | XDG_DATA_DIRS = NA, 22 | XDG_CONFIG_DIRS = NA, 23 | ) 24 | 25 | expect_equal(user_data_dir("R", os = "unix"), "~/.local/share/R") 26 | expect_equal(user_config_dir("R", os = "unix"), "~/.config/R") 27 | expect_equal(site_data_dir("R", os = "unix"), "/usr/local/share/R") 28 | expect_equal(site_config_dir("R", os = "unix"), "/etc/xdg/R") 29 | }) 30 | 31 | test_that("can override linux paths with envvars", { 32 | withr::local_envvar( 33 | XDG_DATA_HOME = "A", 34 | XDG_CONFIG_HOME = "B", 35 | XDG_DATA_DIRS = "C", 36 | XDG_CONFIG_DIRS = "D", 37 | ) 38 | 39 | expect_equal(user_data_dir("R", os = "unix"), "A/R") 40 | expect_equal(user_config_dir("R", os = "unix"), "B/R") 41 | expect_equal(site_data_dir("R", os = "unix"), "C/R") 42 | expect_equal(site_config_dir("R", os = "unix"), "D/R") 43 | }) 44 | 45 | test_that("can override with R_USER_DATA_DIR", { 46 | withr::local_envvar(R_USER_DATA_DIR = "/test") 47 | expect_equal(user_data_dir("R", os = "mac"), "/test/R") 48 | 49 | withr::local_envvar(R_USER_CONFIG_DIR = "/test") 50 | expect_equal(user_config_dir("R", os = "mac"), "/test/R") 51 | }) 52 | 53 | test_that("can optionally use all XDG_DATA_DIRS", { 54 | withr::local_envvar(XDG_DATA_DIRS = "/usr/local/share:/usr/share") 55 | expect_equal( 56 | site_data_dir("R", os = "unix", multipath = TRUE), 57 | c("/usr/local/share/R", "/usr/share/R") 58 | ) 59 | expect_equal( 60 | site_data_dir("R", os = "unix", multipath = FALSE), 61 | "/usr/local/share/R" 62 | ) 63 | }) 64 | 65 | 66 | test_that("default paths work in windows simulation", { 67 | skip_on_os("windows") 68 | expect_equal( 69 | user_data_dir("R", os = "win"), 70 | "/Local Settings/Application Data/R/R" 71 | ) 72 | expect_equal(user_config_dir("R", os = "win"), "/R/R") 73 | expect_equal( 74 | site_data_dir("R", os = "win"), 75 | "/Application Data/R/R" 76 | ) 77 | expect_equal( 78 | site_config_dir("R", os = "win"), 79 | "/Application Data/R/R" 80 | ) 81 | }) 82 | 83 | test_that("can override windows paths with env vars", { 84 | skip_on_os("windows") 85 | withr::local_envvar(LOCALAPPDATA = NA, PROGRAMDATA = NA) 86 | 87 | withr::local_envvar(APPDATA = "C:/config") 88 | expect_equal( 89 | user_config_dir("R", os = "win", roaming = TRUE), 90 | "C:/config/R/R" 91 | ) 92 | 93 | withr::local_envvar("USERPROFILE" = "C:/config1") 94 | expect_equal( 95 | user_config_dir("R", os = "win", roaming = FALSE), 96 | "C:/config1/Local Settings/Application Data/R/R" 97 | ) 98 | 99 | withr::local_envvar("LOCALAPPDATA" = "C:/config2") 100 | expect_equal( 101 | user_config_dir("R", os = "win", roaming = FALSE), 102 | "C:/config2/R/R" 103 | ) 104 | }) 105 | 106 | 107 | test_that("can expand versioned paths", { 108 | expect_equal( 109 | site_data_dir("R", version = "%V", os = "mac", expand = TRUE), 110 | file.path("/Library/Application Support/R", as.character(getRversion())) 111 | ) 112 | expect_equal( 113 | site_data_dir("R", version = "%V", os = "mac", expand = FALSE), 114 | "/Library/Application Support/R/%V" 115 | ) 116 | }) 117 | 118 | # linux ------------------------------------------------------------------- 119 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | check_os <- function(os) { 2 | if (is.null(os)) { 3 | get_os() 4 | } else { 5 | if (length(os) != 1 || !is.character(os)) { 6 | stop("`os` must be a string", call. = FALSE) 7 | } 8 | if (!os %in% c("win", "mac", "unix")) { 9 | stop("`os` must be one of 'win', 'mac', 'unix'", call. = FALSE) 10 | } 11 | os 12 | } 13 | } 14 | 15 | get_os <- function() { 16 | if (.Platform$OS.type == "windows") { 17 | "win" 18 | } else if (Sys.info()["sysname"] == "Darwin") { 19 | "mac" 20 | } else { 21 | "unix" 22 | } 23 | } 24 | 25 | file_path <- function(...) { 26 | paste(c(...), collapse = .Platform$file.sep) 27 | } 28 | 29 | "%||%" <- function(a, b) if (is.null(a)) b else a 30 | 31 | base_path <- function(os, type, win, mac, unix) { 32 | name <- paste0("R_USER_", type, "_DIR") 33 | val <- Sys.getenv(name) 34 | 35 | if (!identical(val, "")) { 36 | val 37 | } else { 38 | switch(check_os(os), win = win, mac = mac, unix = unix) 39 | } 40 | } 41 | 42 | win_path <- function(type_appdata = "common") { 43 | CSIDL_APPDATA <- 26L 44 | CSIDL_COMMON_APPDATA <- 35L 45 | CSIDL_LOCAL_APPDATA <- 28L 46 | 47 | switch( 48 | type_appdata, 49 | roaming = win_path_csidl(CSIDL_APPDATA) %||% win_path_env("roaming"), 50 | local = win_path_csidl(CSIDL_LOCAL_APPDATA) %||% win_path_env("local"), 51 | common = win_path_csidl(CSIDL_COMMON_APPDATA) %||% win_path_env("common") 52 | ) 53 | } 54 | 55 | #' @useDynLib rappdirs, .registration=TRUE 56 | win_path_csidl <- function(csidl) { 57 | stopifnot(is.integer(csidl), length(csidl) == 1) 58 | path <- .Call(win_path_, csidl, PACKAGE = "rappdirs") 59 | path 60 | } 61 | 62 | # How to get reasonable window paths via environmental variables 63 | win_path_env <- function(type) { 64 | if (type == "roaming") { 65 | env_fallback("APPDATA") 66 | } else if (type == "local") { 67 | path <- Sys.getenv("LOCALAPPDATA", unset = NA) 68 | if (is.na(path)) { 69 | # environmental variable not defined in XP 70 | path <- file.path( 71 | env_fallback("USERPROFILE"), 72 | "Local Settings", 73 | "Application Data" 74 | ) 75 | } 76 | path 77 | } else if (type == "common") { 78 | path <- Sys.getenv("PROGRAMDATA", unset = NA) 79 | if (is.na(path)) { 80 | path <- file.path(env_fallback("ALLUSERPROFILE"), "Application Data") 81 | } 82 | path 83 | } else { 84 | stop("invalid `type` argument") 85 | } 86 | } 87 | 88 | env_fallback <- function(env) { 89 | val <- Sys.getenv(env) 90 | 91 | if (identical(val, "")) { 92 | if (get_os() == "win") { 93 | stop("Can't find envvar '", env, "'", call. = FALSE) 94 | } else { 95 | # Fall back so examples still work when not on windows 96 | paste0("<", env, ">") 97 | } 98 | } else { 99 | val 100 | } 101 | } 102 | 103 | # version ----------------------------------------------------------------- 104 | 105 | check_version <- function(version, appname, expand = FALSE) { 106 | if (is.null(appname) && !is.null(version)) { 107 | warning("version is ignored when appname is null", call. = FALSE) 108 | NULL 109 | } else { 110 | if (expand) { 111 | version <- expand_r_libs_specifiers(version) 112 | } 113 | version 114 | } 115 | } 116 | 117 | expand_r_libs_specifiers <- function(x) { 118 | if (is.null(x)) { 119 | return(NULL) 120 | } 121 | rversion <- getRversion() 122 | x <- gsub_special("%V", rversion, x) 123 | x <- gsub_special("%v", paste(rversion$major, rversion$minor, sep = "."), x) 124 | x <- gsub_special("%p", R.version$platform, x) 125 | x <- gsub_special("%o", R.version$os, x) 126 | x <- gsub_special("%a", R.version$arch, x) 127 | x <- gsub("%%", "%", x) 128 | x 129 | } 130 | 131 | gsub_special <- function(pattern, replacement, x) { 132 | gsub(paste0("([^%]|^)", pattern), paste0("\\1", replacement), x) 133 | } 134 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at codeofconduct@posit.co. 63 | All complaints will be reviewed and investigated promptly and fairly. 64 | 65 | All community leaders are obligated to respect the privacy and security of the 66 | reporter of any incident. 67 | 68 | ## Enforcement Guidelines 69 | 70 | Community leaders will follow these Community Impact Guidelines in determining 71 | the consequences for any action they deem in violation of this Code of Conduct: 72 | 73 | ### 1. Correction 74 | 75 | **Community Impact**: Use of inappropriate language or other behavior deemed 76 | unprofessional or unwelcome in the community. 77 | 78 | **Consequence**: A private, written warning from community leaders, providing 79 | clarity around the nature of the violation and an explanation of why the 80 | behavior was inappropriate. A public apology may be requested. 81 | 82 | ### 2. Warning 83 | 84 | **Community Impact**: A violation through a single incident or series of 85 | actions. 86 | 87 | **Consequence**: A warning with consequences for continued behavior. No 88 | interaction with the people involved, including unsolicited interaction with 89 | those enforcing the Code of Conduct, for a specified period of time. This 90 | includes avoiding interactions in community spaces as well as external channels 91 | like social media. Violating these terms may lead to a temporary or permanent 92 | ban. 93 | 94 | ### 3. Temporary Ban 95 | 96 | **Community Impact**: A serious violation of community standards, including 97 | sustained inappropriate behavior. 98 | 99 | **Consequence**: A temporary ban from any sort of interaction or public 100 | communication with the community for a specified period of time. No public or 101 | private interaction with the people involved, including unsolicited interaction 102 | with those enforcing the Code of Conduct, is allowed during this period. 103 | Violating these terms may lead to a permanent ban. 104 | 105 | ### 4. Permanent Ban 106 | 107 | **Community Impact**: Demonstrating a pattern of violation of community 108 | standards, including sustained inappropriate behavior, harassment of an 109 | individual, or aggression toward or disparagement of classes of individuals. 110 | 111 | **Consequence**: A permanent ban from any sort of public interaction within the 112 | community. 113 | 114 | ## Attribution 115 | 116 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 117 | version 2.1, available at 118 | . 119 | 120 | Community Impact Guidelines were inspired by 121 | [Mozilla's code of conduct enforcement ladder][https://github.com/mozilla/inclusion]. 122 | 123 | For answers to common questions about this code of conduct, see the FAQ at 124 | . Translations are available at . 125 | 126 | [homepage]: https://www.contributor-covenant.org 127 | -------------------------------------------------------------------------------- /R/data.R: -------------------------------------------------------------------------------- 1 | #' Path to user config/data directories 2 | #' 3 | #' @description 4 | #' `user_data_dir()` returns path to the user-specific data directory and 5 | #' `user_config_dir()` returns full path to the user-specific configuration 6 | #' directory. These are the same on Windows and Mac but different on Linux. 7 | #' 8 | #' These functions first use `R_USER_DATA_DIR` and `R_USER_CONFIG_DIR` if set. 9 | #' Otherwise, they follow platform conventions. Typical user config and data 10 | #' directories are: 11 | #' 12 | #' * Mac OS X: `~/Library/Application Support/` 13 | #' * Win XP (not roaming): `C:\\Documents and Settings\\\\Data\\\\` 14 | #' * Win XP (roaming): `C:\\Documents and Settings\\\\Local Settings\\Data\\\\` 15 | #' * Win 7 (not roaming): `C:\\Users\\\\AppData\\Local\\\\` 16 | #' * Win 7 (roaming): `C:\\Users\\\\AppData\\Roaming\\\\` 17 | #' 18 | #' Only Linux makes the distinction between config and data: 19 | #' 20 | #' * Data: `~/.local/share/` 21 | #' * Config: `~/.config/` 22 | #' 23 | #' @param appname is the name of application. If NULL, just the system 24 | #' directory is returned. 25 | #' @param appauthor (only required and used on Windows) is the name of the 26 | #' appauthor or distributing body for this application. Typically 27 | #' it is the owning company name. This falls back to appname. 28 | #' @param version is an optional version path element to append to the 29 | #' path. You might want to use this if you want multiple versions 30 | #' of your app to be able to run independently. If used, this 31 | #' would typically be `"."`. Only applied when appname 32 | #' is not NULL. 33 | #' @param roaming (logical, default `FALSE`) can be set `TRUE` to 34 | #' use the Windows roaming appdata directory. That means that for users on 35 | #' a Windows network setup for roaming profiles, this user data will be 36 | #' sync'd on login. See 37 | #' ` 115 | #' * Unix: `/usr/local/share:/usr/share/` 116 | #' * Win XP: `C:\\Documents and Settings\\All Users\\Application Data\\\\` 117 | #' * Vista: (Fail! `C:\\ProgramData` is a hidden *system* directory on Vista.) 118 | #' * Win 7: `C:\\ProgramData\\\\`. Hidden, but writeable on Win 7. 119 | #' 120 | #' Unix also specifies a separate location for user-shared configuration data in \env{$XDG_CONFIG_DIRS}. 121 | #' 122 | #' * Unix: `/etc/xdg/`, in \env{$XDG_CONFIG_HOME} if defined 123 | #' 124 | #' For Unix, this returns the first default. Set the `multipath=TRUE` to guarantee returning all directories. 125 | #' 126 | #' @inheritParams user_data_dir 127 | #' @param multipath is an optional parameter only applicable to *nix 128 | #' which indicates that the entire list of data dirs should be returned 129 | #' By default, the first directory is returned 130 | #' @section Warning: 131 | #' Do not use this on Windows. See the note above for why. 132 | #' @export 133 | site_data_dir <- function( 134 | appname = NULL, 135 | appauthor = appname, 136 | version = NULL, 137 | multipath = FALSE, 138 | expand = TRUE, 139 | os = NULL 140 | ) { 141 | version <- check_version(version, appname, expand) 142 | 143 | switch( 144 | check_os(os), 145 | win = file_path(win_path("common"), appauthor, appname, version), 146 | mac = file_path("/Library/Application Support", appname, version), 147 | unix = file_path_site_unix( 148 | Sys.getenv("XDG_DATA_DIRS", "/usr/local/share:/usr/share"), 149 | appname, 150 | version, 151 | multipath 152 | ) 153 | ) 154 | } 155 | 156 | #' @rdname site_data_dir 157 | #' @export 158 | site_config_dir <- function( 159 | appname = NULL, 160 | appauthor = appname, 161 | version = NULL, 162 | multipath = FALSE, 163 | expand = TRUE, 164 | os = NULL 165 | ) { 166 | version <- check_version(version, appname, expand) 167 | 168 | switch( 169 | check_os(os), 170 | win = file_path(win_path("common"), appauthor, appname, version), 171 | mac = file_path("/Library/Application Support", appname, version), 172 | unix = file_path_site_unix( 173 | Sys.getenv("XDG_CONFIG_DIRS", "/etc/xdg"), 174 | appname, 175 | version, 176 | multipath 177 | ) 178 | ) 179 | } 180 | 181 | # wrapper with `multipath` and use `parse_path_string` for cleaner switch statement 182 | file_path_site_unix <- function( 183 | sys_getenv, 184 | appname, 185 | version, 186 | multipath = FALSE 187 | ) { 188 | paths <- parse_path_string(sys_getenv) 189 | if (multipath) { 190 | vapply( 191 | paths, 192 | file_path, 193 | appname, 194 | version, 195 | FUN.VALUE = character(1), 196 | USE.NAMES = FALSE 197 | ) 198 | } else { 199 | file_path(paths[[1]], appname, version) 200 | } 201 | } 202 | 203 | parse_path_string <- function(path, sep = ":") { 204 | unique(strsplit(path, sep)[[1]]) 205 | } 206 | --------------------------------------------------------------------------------