From f716dddd7405f7b7c7986e8ca784ddc97fe7a79f Mon Sep 17 00:00:00 2001 From: TinasheMTapera Date: Sat, 17 Aug 2024 21:04:22 -0400 Subject: [PATCH] added post about personal packages --- .../execute-results/html.json | 14 + .../04_building-a-personal-package.qmd | 130 +++ renv.lock | 866 +++++++++++++----- renv/.gitignore | 1 + renv/activate.R | 562 +++++++++--- renv/settings.json | 19 + 6 files changed, 1205 insertions(+), 387 deletions(-) create mode 100644 _freeze/posts/04_building-a-personal-package/04_building-a-personal-package/execute-results/html.json create mode 100644 posts/04_building-a-personal-package/04_building-a-personal-package.qmd create mode 100644 renv/settings.json diff --git a/_freeze/posts/04_building-a-personal-package/04_building-a-personal-package/execute-results/html.json b/_freeze/posts/04_building-a-personal-package/04_building-a-personal-package/execute-results/html.json new file mode 100644 index 0000000..3d7dbd8 --- /dev/null +++ b/_freeze/posts/04_building-a-personal-package/04_building-a-personal-package/execute-results/html.json @@ -0,0 +1,14 @@ +{ + "hash": "63d87fb05f078e9cfea3e1f3bc1853c4", + "result": { + "markdown": "---\ntitle: \"Building a Personal Package\"\nauthor: \"Tinashe M. Tapera\"\ndate: \"2024-08-16\"\nimage: https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcG5rOWxoeDBxOG10dTh2OTZtamVsMmJzbmk3M3VkbGM4YmM1NTBscCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/XbJLL1uIH3PwEB2hui/giphy.gif\n---\n\n\nDo you ever find yourself revisiting short code snippets you’ve written over and over\nagain? It’s probably a sign that you should be maintaining a personal R package.\n\n![You should have a package](https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcG5rOWxoeDBxOG10dTh2OTZtamVsMmJzbmk3M3VkbGM4YmM1NTBscCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/XbJLL1uIH3PwEB2hui/giphy.gif)\n\nThere are multiple benefits to writing your own personal package. Some early career\nR programmers believe that package development is a task that you should only \nundertake if you’re creating something particularly novel, elaborate, or serious, \nwhen in truth an R package is just a collection of functions that help you get your\njob done. It can be as complex, or as simple, as you need it to be. Some advantages \ninclude improved code organization, easier code reuse, and better collaboration \nwith others. Additionally, creating your own package allows you to document your\nfunctions and ensure they are well-tested, which can save you time in the long run. \nWhat’s more, you get to practice your package development workflow in a low-stakes \nenvironment, giving you the option to be as formal or informal as you want with \nregards to standardized workflows, tools, and frameworks. For example, I used my \npersonal package as a way to test out a bunch of features from the `fusen` package, \nwhich is a package designed for “notebook-driven-development” that I’ve been \ninvestigating. Importantly, you can use the package to document any particularly \nelegant or novel solutions you might have come up with for niche situations you’ve \nbeen faced with in your work (without a place to put them existing beforehand, \nyou’re less likely to document it when the moment arrives), and by using GitHub, \nhave access to these solutions in a matter of seconds at any machine.\n\nSo, with all of that being said, here are 3 functions I put in my personal package \nto get the ball rolling. Over time, my list of functions will grow and the \npackage’s utility will increase on its own.\n\n## `len_uniq`\n\nIf you ever find yourself doing this pattern often:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nsome_vector %>%\n unique() %>%\n length()\n\n# OR\nlength(unique(some_vector))\n```\n:::\n\n\nIt's time to write a function for it:\n\n\n::: {.cell}\n\n```{.r .cell-code}\n#' len_uniq\n#' \n#' A short hand for unique() %>% length()\n#' \n#' @param vec A vector with a various objects\n#' @return The number of unique objects in the vector\n#' @export\n#'\n#' @examples\nlen_uniq <- function(vec) {\n length(unique(vec))\n}\n```\n:::\n\n\n`fusen` allows me to write all of the function's examples and tests in one single RMarkdown\nor Quarto document. Check out the [repo](https://github.com/TinasheMTapera/tinasheR/blob/main/dev/flat_core.Rmd) to see how it works.\n\n## `sort_uniq`\n\nLikewise, I'm also prone doing this a lot:\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nsome_vec %>%\n unique() %>%\n sort()\n\n# OR \nsort(unique(some_vec))\n```\n:::\n\n\nSo, putting that in a function, I defined:\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n#' sort_uniq\n#' \n#' A Shorthand for unique() %>% sort()\n#'\n#' @param vec A vector that can be reasonably sorted\n#' @return A sorted vector of unique values in the vector\n#' @export\n#'\n#' @examples\nsort_uniq <- function(vec) {\n sort(unique(vec))\n}\n```\n:::\n\n\n## Not %in% operator\n\nThis is a personal pet peeve of mine, so I had to write a function\nfor it. Python's `not in` is just too fun not to emulate in R:\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n#' %!in%\n#' \n#' An operator that negates the %in% operator\n#' \n#' @return boolean\n#' \n#' @export\n`%!in%` <- Negate(`%in%`)\n```\n:::\n\n\nAnd using these 3 functions, I already had enough material to develop\na simple package that includes documentation with Roxygen,\ntesting with `testthat`, and publishing with `pkgdown` — all useful\nskills to know before the day comes that you're asked to build\nsomething \"important\".\n\n## Conclusion\n\nEven with that little effort, we've managed to develop a fully\ndocumented and operational personal R package available on\nGithub for me to use whenever I need my shorthand snippets: [tinasheR](https://tinashemtapera.github.io/tinasheR/). \n\nI hope this might encourage you to develop your own!", + "supporting": [], + "filters": [ + "rmarkdown/pagebreak.lua" + ], + "includes": {}, + "engineDependencies": {}, + "preserve": {}, + "postProcess": true + } +} \ No newline at end of file diff --git a/posts/04_building-a-personal-package/04_building-a-personal-package.qmd b/posts/04_building-a-personal-package/04_building-a-personal-package.qmd new file mode 100644 index 0000000..a97708b --- /dev/null +++ b/posts/04_building-a-personal-package/04_building-a-personal-package.qmd @@ -0,0 +1,130 @@ +--- +title: "Building a Personal Package" +author: "Tinashe M. Tapera" +date: "2024-08-16" +image: https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcG5rOWxoeDBxOG10dTh2OTZtamVsMmJzbmk3M3VkbGM4YmM1NTBscCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/XbJLL1uIH3PwEB2hui/giphy.gif +--- + +Do you ever find yourself revisiting short code snippets you’ve written over and over +again? It’s probably a sign that you should be maintaining a personal R package. + +![You should have a package](https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcG5rOWxoeDBxOG10dTh2OTZtamVsMmJzbmk3M3VkbGM4YmM1NTBscCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/XbJLL1uIH3PwEB2hui/giphy.gif) + +There are multiple benefits to writing your own personal package. Some early career +R programmers believe that package development is a task that you should only +undertake if you’re creating something particularly novel, elaborate, or serious, +when in truth an R package is just a collection of functions that help you get your +job done. It can be as complex, or as simple, as you need it to be. Some advantages +include improved code organization, easier code reuse, and better collaboration +with others. Additionally, creating your own package allows you to document your +functions and ensure they are well-tested, which can save you time in the long run. +What’s more, you get to practice your package development workflow in a low-stakes +environment, giving you the option to be as formal or informal as you want with +regards to standardized workflows, tools, and frameworks. For example, I used my +personal package as a way to test out a bunch of features from the `fusen` package, +which is a package designed for “notebook-driven-development” that I’ve been +investigating. Importantly, you can use the package to document any particularly +elegant or novel solutions you might have come up with for niche situations you’ve +been faced with in your work (without a place to put them existing beforehand, +you’re less likely to document it when the moment arrives), and by using GitHub, +have access to these solutions in a matter of seconds at any machine. + +So, with all of that being said, here are 3 functions I put in my personal package +to get the ball rolling. Over time, my list of functions will grow and the +package’s utility will increase on its own. + +## `len_uniq` + +If you ever find yourself doing this pattern often: + +```{r, eval=FALSE} +some_vector %>% + unique() %>% + length() + +# OR +length(unique(some_vector)) +``` + +It's time to write a function for it: + +```{r function-len_uniq} +#' len_uniq +#' +#' A short hand for unique() %>% length() +#' +#' @param vec A vector with a various objects +#' @return The number of unique objects in the vector +#' @export +#' +#' @examples +len_uniq <- function(vec) { + length(unique(vec)) +} +``` + +`fusen` allows me to write all of the function's examples and tests in one single RMarkdown +or Quarto document. Check out the [repo](https://github.com/TinasheMTapera/tinasheR/blob/main/dev/flat_core.Rmd) to see how it works. + +## `sort_uniq` + +Likewise, I'm also prone doing this a lot: + + +```{r, eval=FALSE} +some_vec %>% + unique() %>% + sort() + +# OR +sort(unique(some_vec)) +``` + +So, putting that in a function, I defined: + + +```{r} +#' sort_uniq +#' +#' A Shorthand for unique() %>% sort() +#' +#' @param vec A vector that can be reasonably sorted +#' @return A sorted vector of unique values in the vector +#' @export +#' +#' @examples +sort_uniq <- function(vec) { + sort(unique(vec)) +} +``` + +## Not %in% operator + +This is a personal pet peeve of mine, so I had to write a function +for it. Python's `not in` is just too fun not to emulate in R: + + +```{r} +#' %!in% +#' +#' An operator that negates the %in% operator +#' +#' @return boolean +#' +#' @export +`%!in%` <- Negate(`%in%`) +``` + +And using these 3 functions, I already had enough material to develop +a simple package that includes documentation with Roxygen, +testing with `testthat`, and publishing with `pkgdown` — all useful +skills to know before the day comes that you're asked to build +something "important". + +## Conclusion + +Even with that little effort, we've managed to develop a fully +documented and operational personal R package available on +Github for me to use whenever I need my shorthand snippets: [tinasheR](https://tinashemtapera.github.io/tinasheR/). + +I hope this might encourage you to develop your own! \ No newline at end of file diff --git a/renv.lock b/renv.lock index d94e371..6e9782f 100644 --- a/renv.lock +++ b/renv.lock @@ -1,6 +1,6 @@ { "R": { - "Version": "4.2.2", + "Version": "4.4.1", "Repositories": [ { "Name": "CRAN", @@ -14,113 +14,155 @@ "Version": "1.1.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "b2866e62bab9378c3cc9476a1954226b", - "Requirements": [] + "Requirements": [ + "R", + "methods" + ], + "Hash": "b2866e62bab9378c3cc9476a1954226b" }, "MASS": { "Package": "MASS", "Version": "7.3-58.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "762e1804143a332333c054759f89a706", - "Requirements": [] + "Requirements": [ + "R", + "grDevices", + "graphics", + "methods", + "stats", + "utils" + ], + "Hash": "762e1804143a332333c054759f89a706" }, "Matrix": { "Package": "Matrix", "Version": "1.6-5", "Source": "Repository", "Repository": "CRAN", - "Hash": "8c7115cd3a0e048bda2a7cd110549f7a", "Requirements": [ - "lattice" - ] + "R", + "grDevices", + "graphics", + "grid", + "lattice", + "methods", + "stats", + "utils" + ], + "Hash": "8c7115cd3a0e048bda2a7cd110549f7a" }, "R6": { "Package": "R6", "Version": "2.5.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "470851b6d5d0ac559e9d01bb352b4021", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "470851b6d5d0ac559e9d01bb352b4021" }, "RColorBrewer": { "Package": "RColorBrewer", "Version": "1.1-3", "Source": "Repository", "Repository": "CRAN", - "Hash": "45f0398006e83a5b10b72a90663d8d8c", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "45f0398006e83a5b10b72a90663d8d8c" }, "Rcpp": { "Package": "Rcpp", "Version": "1.0.9", "Source": "Repository", "Repository": "CRAN", - "Hash": "e9c08b94391e9f3f97355841229124f2", - "Requirements": [] + "Requirements": [ + "methods", + "utils" + ], + "Hash": "e9c08b94391e9f3f97355841229124f2" + }, + "SnowballC": { + "Package": "SnowballC", + "Version": "0.7.1", + "Source": "Repository", + "Repository": "CRAN", + "Hash": "46da3912f69e3e6258a033802c4af32e" }, "askpass": { "Package": "askpass", "Version": "1.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "e8a22846fff485f0be3770c2da758713", "Requirements": [ "sys" - ] + ], + "Hash": "e8a22846fff485f0be3770c2da758713" }, "backports": { "Package": "backports", "Version": "1.4.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "c39fbec8a30d23e721980b8afb31984c", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "c39fbec8a30d23e721980b8afb31984c" }, "base64enc": { "Package": "base64enc", "Version": "0.1-3", "Source": "Repository", "Repository": "CRAN", - "Hash": "543776ae6848fde2f48ff3816d0628bc", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "543776ae6848fde2f48ff3816d0628bc" }, "bit": { "Package": "bit", "Version": "4.0.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "d242abec29412ce988848d0294b208fd", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "d242abec29412ce988848d0294b208fd" }, "bit64": { "Package": "bit64", "Version": "4.0.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "9fe98599ca456d6552421db0d6772d8f", "Requirements": [ - "bit" - ] + "R", + "bit", + "methods", + "stats", + "utils" + ], + "Hash": "9fe98599ca456d6552421db0d6772d8f" }, "blob": { "Package": "blob", "Version": "1.2.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "40415719b5a479b87949f3aa0aee737c", "Requirements": [ + "methods", "rlang", "vctrs" - ] + ], + "Hash": "40415719b5a479b87949f3aa0aee737c" }, "broom": { "Package": "broom", "Version": "1.0.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "fd25391c3c4f6ecf0fa95f1e6d15378c", "Requirements": [ + "R", "backports", "dplyr", "ellipsis", @@ -132,146 +174,172 @@ "stringr", "tibble", "tidyr" - ] + ], + "Hash": "fd25391c3c4f6ecf0fa95f1e6d15378c" }, "bslib": { "Package": "bslib", "Version": "0.4.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "89a0cd0c45161e3bd1c1e74a2d65e516", "Requirements": [ + "R", "cachem", + "grDevices", "htmltools", "jquerylib", "jsonlite", "memoise", "rlang", "sass" - ] + ], + "Hash": "89a0cd0c45161e3bd1c1e74a2d65e516" }, "cachem": { "Package": "cachem", "Version": "1.0.6", "Source": "Repository", "Repository": "CRAN", - "Hash": "648c5b3d71e6a37e3043617489a0a0e9", "Requirements": [ "fastmap", "rlang" - ] + ], + "Hash": "648c5b3d71e6a37e3043617489a0a0e9" }, "callr": { "Package": "callr", "Version": "3.7.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "9b2191ede20fa29828139b9900922e51", "Requirements": [ + "R", "R6", - "processx" - ] + "processx", + "utils" + ], + "Hash": "9b2191ede20fa29828139b9900922e51" }, "cellranger": { "Package": "cellranger", "Version": "1.1.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "f61dbaec772ccd2e17705c1e872e9e7c", "Requirements": [ + "R", "rematch", "tibble" - ] + ], + "Hash": "f61dbaec772ccd2e17705c1e872e9e7c" }, "cli": { "Package": "cli", "Version": "3.6.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "89e6d8219950eac806ae0c489052048a", - "Requirements": [] + "Requirements": [ + "R", + "utils" + ], + "Hash": "89e6d8219950eac806ae0c489052048a" }, "clipr": { "Package": "clipr", "Version": "0.8.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "3f038e5ac7f41d4ac41ce658c85e3042", - "Requirements": [] + "Requirements": [ + "utils" + ], + "Hash": "3f038e5ac7f41d4ac41ce658c85e3042" }, "colorspace": { "Package": "colorspace", "Version": "2.1-0", "Source": "Repository", "Repository": "CRAN", - "Hash": "f20c47fd52fae58b4e377c37bb8c335b", - "Requirements": [] + "Requirements": [ + "R", + "grDevices", + "graphics", + "methods", + "stats" + ], + "Hash": "f20c47fd52fae58b4e377c37bb8c335b" }, "conflicted": { "Package": "conflicted", "Version": "1.2.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "bb097fccb22d156624fd07cd2894ddb6", "Requirements": [ + "R", "cli", "memoise", "rlang" - ] + ], + "Hash": "bb097fccb22d156624fd07cd2894ddb6" }, "cpp11": { "Package": "cpp11", "Version": "0.4.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "ed588261931ee3be2c700d22e94a29ab", - "Requirements": [] + "Hash": "ed588261931ee3be2c700d22e94a29ab" }, "crayon": { "Package": "crayon", "Version": "1.5.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "e8a1e41acf02548751f45c718d55aa6a", - "Requirements": [] + "Requirements": [ + "grDevices", + "methods", + "utils" + ], + "Hash": "e8a1e41acf02548751f45c718d55aa6a" }, "crosstalk": { "Package": "crosstalk", "Version": "1.2.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "ab12c7b080a57475248a30f4db6298c0", "Requirements": [ "R6", "htmltools", "jsonlite", "lazyeval" - ] + ], + "Hash": "ab12c7b080a57475248a30f4db6298c0" }, "curl": { "Package": "curl", - "Version": "4.3.3", + "Version": "5.2.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "0eb86baa62f06e8855258fa5a8048667", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "411ca2c03b1ce5f548345d2fc2685f7a" }, "data.table": { "Package": "data.table", "Version": "1.14.8", "Source": "Repository", "Repository": "CRAN", - "Hash": "b4c06e554f33344e044ccd7fdca750a9", - "Requirements": [] + "Requirements": [ + "R", + "methods" + ], + "Hash": "b4c06e554f33344e044ccd7fdca750a9" }, "dbplyr": { "Package": "dbplyr", "Version": "2.3.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "d6fd1b1440c1cacc6623aaa4e9fe352b", "Requirements": [ "DBI", + "R", "R6", "blob", "cli", @@ -279,51 +347,60 @@ "glue", "lifecycle", "magrittr", + "methods", "pillar", "purrr", "rlang", "tibble", "tidyr", "tidyselect", + "utils", "vctrs", "withr" - ] + ], + "Hash": "d6fd1b1440c1cacc6623aaa4e9fe352b" }, "digest": { "Package": "digest", "Version": "0.6.33", "Source": "Repository", "Repository": "CRAN", - "Hash": "b18a9cf3c003977b0cc49d5e76ebe48d", - "Requirements": [] + "Requirements": [ + "R", + "utils" + ], + "Hash": "b18a9cf3c003977b0cc49d5e76ebe48d" }, "dplyr": { "Package": "dplyr", "Version": "1.1.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "e85ffbebaad5f70e1a2e2ef4302b4949", "Requirements": [ + "R", "R6", "cli", "generics", "glue", "lifecycle", "magrittr", + "methods", "pillar", "rlang", "tibble", "tidyselect", + "utils", "vctrs" - ] + ], + "Hash": "e85ffbebaad5f70e1a2e2ef4302b4949" }, "dtplyr": { "Package": "dtplyr", "Version": "1.3.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "54ed3ea01b11e81a86544faaecfef8e2", "Requirements": [ + "R", "cli", "data.table", "dplyr", @@ -333,91 +410,103 @@ "tibble", "tidyselect", "vctrs" - ] + ], + "Hash": "54ed3ea01b11e81a86544faaecfef8e2" }, "ellipsis": { "Package": "ellipsis", "Version": "0.3.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "bb0eec2fe32e88d9e2836c2f73ea2077", "Requirements": [ + "R", "rlang" - ] + ], + "Hash": "bb0eec2fe32e88d9e2836c2f73ea2077" }, "evaluate": { "Package": "evaluate", "Version": "0.22", "Source": "Repository", "Repository": "CRAN", - "Hash": "66f39c7a21e03c4dcb2c2d21d738d603", - "Requirements": [] + "Requirements": [ + "R", + "methods" + ], + "Hash": "66f39c7a21e03c4dcb2c2d21d738d603" }, "fansi": { "Package": "fansi", "Version": "1.0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "83a8afdbe71839506baa9f90eebad7ec", - "Requirements": [] + "Requirements": [ + "R", + "grDevices", + "utils" + ], + "Hash": "83a8afdbe71839506baa9f90eebad7ec" }, "farver": { "Package": "farver", "Version": "2.1.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "8106d78941f34855c440ddb946b8f7a5", - "Requirements": [] + "Hash": "8106d78941f34855c440ddb946b8f7a5" }, "fastmap": { "Package": "fastmap", "Version": "1.1.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "77bd60a6157420d4ffa93b27cf6a58b8", - "Requirements": [] + "Hash": "77bd60a6157420d4ffa93b27cf6a58b8" }, "fontawesome": { "Package": "fontawesome", "Version": "0.5.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "e80750aec5717dedc019ad7ee40e4a7c", "Requirements": [ + "R", "htmltools", "rlang" - ] + ], + "Hash": "e80750aec5717dedc019ad7ee40e4a7c" }, "forcats": { "Package": "forcats", "Version": "1.0.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "1a0a9a3d5083d0d573c4214576f1e690", "Requirements": [ + "R", "cli", "glue", "lifecycle", "magrittr", "rlang", "tibble" - ] + ], + "Hash": "1a0a9a3d5083d0d573c4214576f1e690" }, "fs": { "Package": "fs", - "Version": "1.5.2", + "Version": "1.6.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "7c89603d81793f0d5486d91ab1fc6f1d", - "Requirements": [] + "Requirements": [ + "R", + "methods" + ], + "Hash": "15aeb8c27f5ea5161f9f6a641fafd93a" }, "gargle": { "Package": "gargle", "Version": "1.5.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "fc0b272e5847c58cd5da9b20eedbd026", "Requirements": [ + "R", "cli", "fs", "glue", @@ -427,53 +516,66 @@ "openssl", "rappdirs", "rlang", + "stats", + "utils", "withr" - ] + ], + "Hash": "fc0b272e5847c58cd5da9b20eedbd026" }, "generics": { "Package": "generics", "Version": "0.1.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "15e9634c0fcd294799e9b2e929ed1b86", - "Requirements": [] + "Requirements": [ + "R", + "methods" + ], + "Hash": "15e9634c0fcd294799e9b2e929ed1b86" }, "ggplot2": { "Package": "ggplot2", "Version": "3.4.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "85846544c596e71f8f46483ab165da33", "Requirements": [ "MASS", + "R", "cli", "glue", + "grDevices", + "grid", "gtable", "isoband", "lifecycle", "mgcv", "rlang", "scales", + "stats", "tibble", "vctrs", "withr" - ] + ], + "Hash": "85846544c596e71f8f46483ab165da33" }, "glue": { "Package": "glue", "Version": "1.6.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "4f2596dfb05dac67b9dc558e5c6fba2e", - "Requirements": [] + "Requirements": [ + "R", + "methods" + ], + "Hash": "4f2596dfb05dac67b9dc558e5c6fba2e" }, "googledrive": { "Package": "googledrive", "Version": "2.1.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "e99641edef03e2a5e87f0a0b1fcc97f4", "Requirements": [ + "R", "cli", "gargle", "glue", @@ -485,18 +587,20 @@ "purrr", "rlang", "tibble", + "utils", "uuid", "vctrs", "withr" - ] + ], + "Hash": "e99641edef03e2a5e87f0a0b1fcc97f4" }, "googlesheets4": { "Package": "googlesheets4", "Version": "1.1.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "d6db1667059d027da730decdc214b959", "Requirements": [ + "R", "cellranger", "cli", "curl", @@ -507,265 +611,368 @@ "ids", "lifecycle", "magrittr", + "methods", "purrr", "rematch2", "rlang", "tibble", + "utils", "vctrs", "withr" - ] + ], + "Hash": "d6db1667059d027da730decdc214b959" }, "gtable": { "Package": "gtable", "Version": "0.3.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "b44addadb528a0d227794121c00572a0", "Requirements": [ + "R", "cli", "glue", + "grid", "lifecycle", "rlang" - ] + ], + "Hash": "b44addadb528a0d227794121c00572a0" }, "haven": { "Package": "haven", "Version": "2.5.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "9b302fe352f9cfc5dcf0a4139af3a565", "Requirements": [ + "R", "cli", "cpp11", "forcats", "hms", "lifecycle", + "methods", "readr", "rlang", "tibble", "tidyselect", "vctrs" - ] + ], + "Hash": "9b302fe352f9cfc5dcf0a4139af3a565" }, "highr": { "Package": "highr", "Version": "0.10", "Source": "Repository", "Repository": "CRAN", - "Hash": "06230136b2d2b9ba5805e1963fa6e890", "Requirements": [ + "R", "xfun" - ] + ], + "Hash": "06230136b2d2b9ba5805e1963fa6e890" }, "hms": { "Package": "hms", "Version": "1.1.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "41100392191e1244b887878b533eea91", "Requirements": [ "ellipsis", "lifecycle", + "methods", "pkgconfig", "rlang", "vctrs" - ] + ], + "Hash": "41100392191e1244b887878b533eea91" }, "htmltools": { "Package": "htmltools", "Version": "0.5.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "9d27e99cc90bd701c0a7a63e5923f9b7", "Requirements": [ + "R", "base64enc", "digest", "ellipsis", "fastmap", - "rlang" - ] + "grDevices", + "rlang", + "utils" + ], + "Hash": "9d27e99cc90bd701c0a7a63e5923f9b7" }, "htmlwidgets": { "Package": "htmlwidgets", "Version": "1.6.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "a865aa85bcb2697f47505bfd70422471", "Requirements": [ + "grDevices", "htmltools", "jsonlite", "knitr", "rmarkdown", "yaml" - ] + ], + "Hash": "a865aa85bcb2697f47505bfd70422471" }, "httr": { "Package": "httr", "Version": "1.4.6", "Source": "Repository", "Repository": "CRAN", - "Hash": "7e5e3cbd2a7bc07880c94e22348fb661", "Requirements": [ + "R", "R6", "curl", "jsonlite", "mime", "openssl" - ] + ], + "Hash": "7e5e3cbd2a7bc07880c94e22348fb661" + }, + "httr2": { + "Package": "httr2", + "Version": "1.0.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "R6", + "cli", + "curl", + "glue", + "lifecycle", + "magrittr", + "openssl", + "rappdirs", + "rlang", + "vctrs", + "withr" + ], + "Hash": "320c8fe23fcb25a6690ef7bdb6a3a705" }, "ids": { "Package": "ids", "Version": "1.0.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "99df65cfef20e525ed38c3d2577f7190", "Requirements": [ "openssl", "uuid" - ] + ], + "Hash": "99df65cfef20e525ed38c3d2577f7190" }, "isoband": { "Package": "isoband", "Version": "0.2.7", "Source": "Repository", "Repository": "CRAN", - "Hash": "0080607b4a1a7b28979aecef976d8bc2", - "Requirements": [] + "Requirements": [ + "grid", + "utils" + ], + "Hash": "0080607b4a1a7b28979aecef976d8bc2" + }, + "janeaustenr": { + "Package": "janeaustenr", + "Version": "1.0.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "26f391e42073877818f2d4f0470dca24" }, "jquerylib": { "Package": "jquerylib", "Version": "0.1.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "5aab57a3bd297eee1c1d862735972182", "Requirements": [ "htmltools" - ] + ], + "Hash": "5aab57a3bd297eee1c1d862735972182" }, "jsonlite": { "Package": "jsonlite", "Version": "1.8.7", "Source": "Repository", "Repository": "CRAN", - "Hash": "266a20443ca13c65688b2116d5220f76", - "Requirements": [] + "Requirements": [ + "methods" + ], + "Hash": "266a20443ca13c65688b2116d5220f76" + }, + "kableExtra": { + "Package": "kableExtra", + "Version": "1.4.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "digest", + "grDevices", + "graphics", + "htmltools", + "knitr", + "magrittr", + "rmarkdown", + "rstudioapi", + "scales", + "stats", + "stringr", + "svglite", + "tools", + "viridisLite", + "xml2" + ], + "Hash": "532d16304274c23c8563f94b79351c86" }, "knitr": { "Package": "knitr", "Version": "1.42", "Source": "Repository", "Repository": "CRAN", - "Hash": "8329a9bcc82943c8069104d4be3ee22d", "Requirements": [ + "R", "evaluate", "highr", + "methods", + "tools", "xfun", "yaml" - ] + ], + "Hash": "8329a9bcc82943c8069104d4be3ee22d" }, "labeling": { "Package": "labeling", "Version": "0.4.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "3d5108641f47470611a32d0bdf357a72", - "Requirements": [] + "Requirements": [ + "graphics", + "stats" + ], + "Hash": "3d5108641f47470611a32d0bdf357a72" }, "later": { "Package": "later", "Version": "1.3.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "7e7b457d7766bc47f2a5f21cc2984f8e", "Requirements": [ "Rcpp", "rlang" - ] + ], + "Hash": "7e7b457d7766bc47f2a5f21cc2984f8e" }, "lattice": { "Package": "lattice", "Version": "0.20-45", "Source": "Repository", "Repository": "CRAN", - "Hash": "b64cdbb2b340437c4ee047a1f4c4377b", - "Requirements": [] + "Requirements": [ + "R", + "grDevices", + "graphics", + "grid", + "stats", + "utils" + ], + "Hash": "b64cdbb2b340437c4ee047a1f4c4377b" }, "lazyeval": { "Package": "lazyeval", "Version": "0.2.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "d908914ae53b04d4c0c0fd72ecc35370", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "d908914ae53b04d4c0c0fd72ecc35370" }, "lifecycle": { "Package": "lifecycle", "Version": "1.0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "001cecbeac1cff9301bdc3775ee46a86", "Requirements": [ + "R", "cli", "glue", "rlang" - ] + ], + "Hash": "001cecbeac1cff9301bdc3775ee46a86" }, "lubridate": { "Package": "lubridate", "Version": "1.9.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "e25f18436e3efd42c7c590a1c4c15390", "Requirements": [ + "R", "generics", + "methods", "timechange" - ] + ], + "Hash": "e25f18436e3efd42c7c590a1c4c15390" }, "magrittr": { "Package": "magrittr", "Version": "2.0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "7ce2733a9826b3aeb1775d56fd305472", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "7ce2733a9826b3aeb1775d56fd305472" }, "memoise": { "Package": "memoise", "Version": "2.0.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c", "Requirements": [ "cachem", "rlang" - ] + ], + "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c" }, "mgcv": { "Package": "mgcv", "Version": "1.8-41", "Source": "Repository", "Repository": "CRAN", - "Hash": "6b3904f13346742caa3e82dd0303d4ad", "Requirements": [ "Matrix", - "nlme" - ] + "R", + "graphics", + "methods", + "nlme", + "splines", + "stats", + "utils" + ], + "Hash": "6b3904f13346742caa3e82dd0303d4ad" }, "mime": { "Package": "mime", "Version": "0.12", "Source": "Repository", "Repository": "CRAN", - "Hash": "18e9c28c1d3ca1560ce30658b22ce104", - "Requirements": [] + "Requirements": [ + "tools" + ], + "Hash": "18e9c28c1d3ca1560ce30658b22ce104" }, "modelr": { "Package": "modelr", "Version": "0.1.11", "Source": "Repository", "Repository": "CRAN", - "Hash": "4f50122dc256b1b6996a4703fecea821", "Requirements": [ + "R", "broom", "magrittr", "purrr", @@ -774,44 +981,49 @@ "tidyr", "tidyselect", "vctrs" - ] + ], + "Hash": "4f50122dc256b1b6996a4703fecea821" }, "munsell": { "Package": "munsell", "Version": "0.5.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "6dfe8bf774944bd5595785e3229d8771", "Requirements": [ - "colorspace" - ] + "colorspace", + "methods" + ], + "Hash": "6dfe8bf774944bd5595785e3229d8771" }, "nlme": { "Package": "nlme", "Version": "3.1-160", "Source": "Repository", "Repository": "CRAN", - "Hash": "02e3c6e7df163aafa8477225e6827bc5", "Requirements": [ - "lattice" - ] + "R", + "graphics", + "lattice", + "stats", + "utils" + ], + "Hash": "02e3c6e7df163aafa8477225e6827bc5" }, "openssl": { "Package": "openssl", "Version": "2.0.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "b04c27110bf367b4daa93f34f3d58e75", "Requirements": [ "askpass" - ] + ], + "Hash": "b04c27110bf367b4daa93f34f3d58e75" }, "pillar": { "Package": "pillar", "Version": "1.9.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "15da5a8412f317beeee6175fbc76f4bb", "Requirements": [ "cli", "fansi", @@ -819,24 +1031,28 @@ "lifecycle", "rlang", "utf8", + "utils", "vctrs" - ] + ], + "Hash": "15da5a8412f317beeee6175fbc76f4bb" }, "pkgconfig": { "Package": "pkgconfig", "Version": "2.0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "01f28d4278f15c76cddbea05899c5d6f", - "Requirements": [] + "Requirements": [ + "utils" + ], + "Hash": "01f28d4278f15c76cddbea05899c5d6f" }, "plotly": { "Package": "plotly", "Version": "4.10.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "a1ac5c03ad5ad12b9d1597e00e23c3dd", "Requirements": [ + "R", "RColorBrewer", "base64enc", "crosstalk", @@ -856,104 +1072,114 @@ "scales", "tibble", "tidyr", + "tools", "vctrs", "viridisLite" - ] + ], + "Hash": "a1ac5c03ad5ad12b9d1597e00e23c3dd" }, "prettyunits": { "Package": "prettyunits", "Version": "1.1.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "95ef9167b75dde9d2ccc3c7528393e7e", - "Requirements": [] + "Hash": "95ef9167b75dde9d2ccc3c7528393e7e" }, "processx": { "Package": "processx", "Version": "3.8.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "3efbd8ac1be0296a46c55387aeace0f3", "Requirements": [ + "R", "R6", - "ps" - ] + "ps", + "utils" + ], + "Hash": "3efbd8ac1be0296a46c55387aeace0f3" }, "progress": { "Package": "progress", "Version": "1.2.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "14dc9f7a3c91ebb14ec5bb9208a07061", "Requirements": [ "R6", "crayon", "hms", "prettyunits" - ] + ], + "Hash": "14dc9f7a3c91ebb14ec5bb9208a07061" }, "promises": { "Package": "promises", "Version": "1.2.0.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "4ab2c43adb4d4699cf3690acd378d75d", "Requirements": [ "R6", "Rcpp", "later", "magrittr", - "rlang" - ] + "rlang", + "stats" + ], + "Hash": "4ab2c43adb4d4699cf3690acd378d75d" }, "ps": { "Package": "ps", "Version": "1.7.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "709d852d33178db54b17c722e5b1e594", - "Requirements": [] + "Requirements": [ + "R", + "utils" + ], + "Hash": "709d852d33178db54b17c722e5b1e594" }, "purrr": { "Package": "purrr", "Version": "1.0.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "1cba04a4e9414bdefc9dcaa99649a8dc", "Requirements": [ + "R", "cli", "lifecycle", "magrittr", "rlang", "vctrs" - ] + ], + "Hash": "1cba04a4e9414bdefc9dcaa99649a8dc" }, "ragg": { "Package": "ragg", "Version": "1.2.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "690bc058ea2b1b8a407d3cfe3dce3ef9", "Requirements": [ "systemfonts", "textshaping" - ] + ], + "Hash": "690bc058ea2b1b8a407d3cfe3dce3ef9" }, "rappdirs": { "Package": "rappdirs", "Version": "0.3.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "5e3c5dc0b071b21fa128676560dbe94d", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "5e3c5dc0b071b21fa128676560dbe94d" }, "readr": { "Package": "readr", "Version": "2.1.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "b5047343b3825f37ad9d3b5d89aa1078", "Requirements": [ + "R", "R6", "cli", "clipr", @@ -961,58 +1187,64 @@ "crayon", "hms", "lifecycle", + "methods", "rlang", "tibble", "tzdb", + "utils", "vroom" - ] + ], + "Hash": "b5047343b3825f37ad9d3b5d89aa1078" }, "readxl": { "Package": "readxl", "Version": "1.4.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "8cf9c239b96df1bbb133b74aef77ad0a", "Requirements": [ + "R", "cellranger", "cpp11", "progress", - "tibble" - ] + "tibble", + "utils" + ], + "Hash": "8cf9c239b96df1bbb133b74aef77ad0a" }, "rematch": { "Package": "rematch", "Version": "1.0.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "c66b930d20bb6d858cd18e1cebcfae5c", - "Requirements": [] + "Hash": "c66b930d20bb6d858cd18e1cebcfae5c" }, "rematch2": { "Package": "rematch2", "Version": "2.1.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "76c9e04c712a05848ae7a23d2f170a40", "Requirements": [ "tibble" - ] + ], + "Hash": "76c9e04c712a05848ae7a23d2f170a40" }, "renv": { "Package": "renv", - "Version": "0.15.5", + "Version": "1.0.7", "Source": "Repository", "Repository": "CRAN", - "Hash": "6a38294e7d12f5d8e656b08c5bd8ae34", - "Requirements": [] + "Requirements": [ + "utils" + ], + "Hash": "397b7b2a265bc5a7a06852524dabae20" }, "reprex": { "Package": "reprex", "Version": "2.0.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "d66fe009d4c20b7ab1927eb405db9ee2", "Requirements": [ + "R", "callr", "cli", "clipr", @@ -1023,24 +1255,29 @@ "rlang", "rmarkdown", "rstudioapi", + "utils", "withr" - ] + ], + "Hash": "d66fe009d4c20b7ab1927eb405db9ee2" }, "rlang": { "Package": "rlang", "Version": "1.1.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "a85c767b55f0bf9b7ad16c6d7baee5bb", - "Requirements": [] + "Requirements": [ + "R", + "utils" + ], + "Hash": "a85c767b55f0bf9b7ad16c6d7baee5bb" }, "rmarkdown": { "Package": "rmarkdown", "Version": "2.21", "Source": "Repository", "Repository": "CRAN", - "Hash": "493df4ae51e2e984952ea4d5c75786a3", "Requirements": [ + "R", "bslib", "evaluate", "fontawesome", @@ -1048,27 +1285,53 @@ "jquerylib", "jsonlite", "knitr", + "methods", "stringr", "tinytex", + "tools", + "utils", "xfun", "yaml" - ] + ], + "Hash": "493df4ae51e2e984952ea4d5c75786a3" }, "rstudioapi": { "Package": "rstudioapi", "Version": "0.15.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "5564500e25cffad9e22244ced1379887", - "Requirements": [] + "Hash": "5564500e25cffad9e22244ced1379887" + }, + "rtweet": { + "Package": "rtweet", + "Version": "2.0.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "bit64", + "curl", + "httr", + "httr2", + "jsonlite", + "lifecycle", + "methods", + "progress", + "rlang", + "tibble", + "tools", + "utils", + "withr" + ], + "Hash": "76c5253622f3de1d506184981386ffa3" }, "rvest": { "Package": "rvest", "Version": "1.0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "a4a5ac819a467808c60e36e92ddf195e", "Requirements": [ + "R", "cli", "glue", "httr", @@ -1079,29 +1342,30 @@ "tibble", "withr", "xml2" - ] + ], + "Hash": "a4a5ac819a467808c60e36e92ddf195e" }, "sass": { "Package": "sass", "Version": "0.4.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "c76cbac7ca04ce82d8c38e29729987a3", "Requirements": [ "R6", "fs", "htmltools", "rappdirs", "rlang" - ] + ], + "Hash": "c76cbac7ca04ce82d8c38e29729987a3" }, "scales": { "Package": "scales", "Version": "1.2.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "906cb23d2f1c5680b8ce439b44c6fa63", "Requirements": [ + "R", "R6", "RColorBrewer", "farver", @@ -1110,34 +1374,53 @@ "munsell", "rlang", "viridisLite" - ] + ], + "Hash": "906cb23d2f1c5680b8ce439b44c6fa63" }, "selectr": { "Package": "selectr", "Version": "0.4-2", "Source": "Repository", "Repository": "CRAN", - "Hash": "3838071b66e0c566d55cc26bd6e27bf4", "Requirements": [ + "R", "R6", + "methods", "stringr" - ] + ], + "Hash": "3838071b66e0c566d55cc26bd6e27bf4" + }, + "splitstackshape": { + "Package": "splitstackshape", + "Version": "1.4.8", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "data.table" + ], + "Hash": "69b26ceb9f7976f347049b4d470c2d65" }, "stringi": { "Package": "stringi", "Version": "1.7.8", "Source": "Repository", "Repository": "CRAN", - "Hash": "a68b980681bcbc84c7a67003fa796bfb", - "Requirements": [] + "Requirements": [ + "R", + "stats", + "tools", + "utils" + ], + "Hash": "a68b980681bcbc84c7a67003fa796bfb" }, "stringr": { "Package": "stringr", "Version": "1.5.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "671a4d384ae9d32fc47a14e98bfa3dc8", "Requirements": [ + "R", "cli", "glue", "lifecycle", @@ -1145,60 +1428,77 @@ "rlang", "stringi", "vctrs" - ] + ], + "Hash": "671a4d384ae9d32fc47a14e98bfa3dc8" + }, + "svglite": { + "Package": "svglite", + "Version": "2.1.3", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "cpp11", + "systemfonts" + ], + "Hash": "124a41fdfa23e8691cb744c762f10516" }, "sys": { "Package": "sys", "Version": "3.4.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "34c16f1ef796057bfa06d3f4ff818a5d", - "Requirements": [] + "Hash": "34c16f1ef796057bfa06d3f4ff818a5d" }, "systemfonts": { "Package": "systemfonts", "Version": "1.0.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "90b28393209827327de889f49935140a", "Requirements": [ + "R", "cpp11" - ] + ], + "Hash": "90b28393209827327de889f49935140a" }, "textshaping": { "Package": "textshaping", "Version": "0.3.6", "Source": "Repository", "Repository": "CRAN", - "Hash": "1ab6223d3670fac7143202cb6a2d43d5", "Requirements": [ + "R", "cpp11", "systemfonts" - ] + ], + "Hash": "1ab6223d3670fac7143202cb6a2d43d5" }, "tibble": { "Package": "tibble", "Version": "3.2.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "a84e2cc86d07289b3b6f5069df7a004c", "Requirements": [ + "R", "fansi", "lifecycle", "magrittr", + "methods", "pillar", "pkgconfig", "rlang", + "utils", "vctrs" - ] + ], + "Hash": "a84e2cc86d07289b3b6f5069df7a004c" }, "tidyr": { "Package": "tidyr", "Version": "1.3.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "e47debdc7ce599b070c8e78e8ac0cfcf", "Requirements": [ + "R", "cli", "cpp11", "dplyr", @@ -1210,31 +1510,57 @@ "stringr", "tibble", "tidyselect", + "utils", "vctrs" - ] + ], + "Hash": "e47debdc7ce599b070c8e78e8ac0cfcf" }, "tidyselect": { "Package": "tidyselect", "Version": "1.2.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "79540e5fcd9e0435af547d885f184fd5", "Requirements": [ + "R", "cli", "glue", "lifecycle", "rlang", "vctrs", "withr" - ] + ], + "Hash": "79540e5fcd9e0435af547d885f184fd5" + }, + "tidytext": { + "Package": "tidytext", + "Version": "0.4.2", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "Matrix", + "R", + "cli", + "dplyr", + "generics", + "janeaustenr", + "lifecycle", + "methods", + "purrr", + "rlang", + "stringr", + "tibble", + "tokenizers", + "vctrs" + ], + "Hash": "612125521ebc22fd028182761211b5d9" }, "tidyverse": { "Package": "tidyverse", "Version": "2.0.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "c328568cd14ea89a83bd4ca7f54ae07e", "Requirements": [ + "R", "broom", "cli", "conflicted", @@ -1265,82 +1591,105 @@ "tibble", "tidyr", "xml2" - ] + ], + "Hash": "c328568cd14ea89a83bd4ca7f54ae07e" }, "timechange": { "Package": "timechange", "Version": "0.2.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "8548b44f79a35ba1791308b61e6012d7", "Requirements": [ + "R", "cpp11" - ] + ], + "Hash": "8548b44f79a35ba1791308b61e6012d7" }, "tinytex": { "Package": "tinytex", "Version": "0.44", "Source": "Repository", "Repository": "CRAN", - "Hash": "c0f007e2eeed7722ce13d42b84a22e07", "Requirements": [ "xfun" - ] + ], + "Hash": "c0f007e2eeed7722ce13d42b84a22e07" + }, + "tokenizers": { + "Package": "tokenizers", + "Version": "0.3.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "Rcpp", + "SnowballC", + "stringi" + ], + "Hash": "76d35ebfaaf291e08c15696c9f2ec96d" }, "tzdb": { "Package": "tzdb", "Version": "0.4.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "f561504ec2897f4d46f0c7657e488ae1", "Requirements": [ + "R", "cpp11" - ] + ], + "Hash": "f561504ec2897f4d46f0c7657e488ae1" }, "utf8": { "Package": "utf8", "Version": "1.2.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "c9c462b759a5cc844ae25b5942654d13", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "c9c462b759a5cc844ae25b5942654d13" }, "uuid": { "Package": "uuid", "Version": "1.1-0", "Source": "Repository", "Repository": "CRAN", - "Hash": "f1cb46c157d080b729159d407be83496", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "f1cb46c157d080b729159d407be83496" }, "vctrs": { "Package": "vctrs", "Version": "0.6.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "d0ef2856b83dc33ea6e255caf6229ee2", "Requirements": [ + "R", "cli", "glue", "lifecycle", "rlang" - ] + ], + "Hash": "d0ef2856b83dc33ea6e255caf6229ee2" }, "viridisLite": { "Package": "viridisLite", "Version": "0.4.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "c826c7c4241b6fc89ff55aaea3fa7491", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "c826c7c4241b6fc89ff55aaea3fa7491" }, "vroom": { "Package": "vroom", "Version": "1.6.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "64f81fdead6e0d250fb041e175d123ab", "Requirements": [ + "R", "bit64", "cli", "cpp11", @@ -1348,46 +1697,73 @@ "glue", "hms", "lifecycle", + "methods", "progress", "rlang", + "stats", "tibble", "tidyselect", "tzdb", "vctrs", "withr" - ] + ], + "Hash": "64f81fdead6e0d250fb041e175d123ab" }, "withr": { "Package": "withr", "Version": "2.5.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "c0e49a9760983e81e55cdd9be92e7182", - "Requirements": [] + "Requirements": [ + "R", + "grDevices", + "graphics", + "stats" + ], + "Hash": "c0e49a9760983e81e55cdd9be92e7182" + }, + "wordcloud": { + "Package": "wordcloud", + "Version": "2.6", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "RColorBrewer", + "Rcpp", + "methods" + ], + "Hash": "dddb6538141ed1e2435cb63c6c748d16" }, "xfun": { "Package": "xfun", "Version": "0.37", "Source": "Repository", "Repository": "CRAN", - "Hash": "a6860e1400a8fd1ddb6d9b4230cc34ab", - "Requirements": [] + "Requirements": [ + "stats", + "tools" + ], + "Hash": "a6860e1400a8fd1ddb6d9b4230cc34ab" }, "xml2": { "Package": "xml2", - "Version": "1.3.3", + "Version": "1.3.6", "Source": "Repository", "Repository": "CRAN", - "Hash": "40682ed6a969ea5abfd351eb67833adc", - "Requirements": [] + "Requirements": [ + "R", + "cli", + "methods", + "rlang" + ], + "Hash": "1d0336142f4cd25d8d23cd3ba7a8fb61" }, "yaml": { "Package": "yaml", "Version": "2.3.6", "Source": "Repository", "Repository": "CRAN", - "Hash": "9b570515751dcbae610f29885e025b41", - "Requirements": [] + "Hash": "9b570515751dcbae610f29885e025b41" } } } diff --git a/renv/.gitignore b/renv/.gitignore index 275e4ca..22a0d01 100644 --- a/renv/.gitignore +++ b/renv/.gitignore @@ -1,3 +1,4 @@ +sandbox/ library/ local/ cellar/ diff --git a/renv/activate.R b/renv/activate.R index 72c0818..d13f993 100644 --- a/renv/activate.R +++ b/renv/activate.R @@ -2,10 +2,28 @@ local({ # the requested version of renv - version <- "0.15.5" + version <- "1.0.7" + attr(version, "sha") <- NULL # the project directory - project <- getwd() + project <- Sys.getenv("RENV_PROJECT") + if (!nzchar(project)) + project <- getwd() + + # use start-up diagnostics if enabled + diagnostics <- Sys.getenv("RENV_STARTUP_DIAGNOSTICS", unset = "FALSE") + if (diagnostics) { + start <- Sys.time() + profile <- tempfile("renv-startup-", fileext = ".Rprof") + utils::Rprof(profile) + on.exit({ + utils::Rprof(NULL) + elapsed <- signif(difftime(Sys.time(), start, units = "auto"), digits = 2L) + writeLines(sprintf("- renv took %s to run the autoloader.", format(elapsed))) + writeLines(sprintf("- Profile: %s", profile)) + print(utils::summaryRprof(profile)) + }, add = TRUE) + } # figure out whether the autoloader is enabled enabled <- local({ @@ -15,6 +33,14 @@ local({ if (!is.null(override)) return(override) + # if we're being run in a context where R_LIBS is already set, + # don't load -- presumably we're being run as a sub-process and + # the parent process has already set up library paths for us + rcmd <- Sys.getenv("R_CMD", unset = NA) + rlibs <- Sys.getenv("R_LIBS", unset = NA) + if (!is.na(rlibs) && !is.na(rcmd)) + return(FALSE) + # next, check environment variables # TODO: prefer using the configuration one in the future envvars <- c( @@ -34,9 +60,22 @@ local({ }) - if (!enabled) + # bail if we're not enabled + if (!enabled) { + + # if we're not enabled, we might still need to manually load + # the user profile here + profile <- Sys.getenv("R_PROFILE_USER", unset = "~/.Rprofile") + if (file.exists(profile)) { + cfg <- Sys.getenv("RENV_CONFIG_USER_PROFILE", unset = "TRUE") + if (tolower(cfg) %in% c("true", "t", "1")) + sys.source(profile, envir = globalenv()) + } + return(FALSE) + } + # avoid recursion if (identical(getOption("renv.autoloader.running"), TRUE)) { warning("ignoring recursive attempt to run renv autoloader") @@ -60,21 +99,90 @@ local({ # load bootstrap tools `%||%` <- function(x, y) { - if (is.environment(x) || length(x)) x else y + if (is.null(x)) y else x + } + + catf <- function(fmt, ..., appendLF = TRUE) { + + quiet <- getOption("renv.bootstrap.quiet", default = FALSE) + if (quiet) + return(invisible()) + + msg <- sprintf(fmt, ...) + cat(msg, file = stdout(), sep = if (appendLF) "\n" else "") + + invisible(msg) + + } + + header <- function(label, + ..., + prefix = "#", + suffix = "-", + n = min(getOption("width"), 78)) + { + label <- sprintf(label, ...) + n <- max(n - nchar(label) - nchar(prefix) - 2L, 8L) + if (n <= 0) + return(paste(prefix, label)) + + tail <- paste(rep.int(suffix, n), collapse = "") + paste0(prefix, " ", label, " ", tail) + + } + + heredoc <- function(text, leave = 0) { + + # remove leading, trailing whitespace + trimmed <- gsub("^\\s*\\n|\\n\\s*$", "", text) + + # split into lines + lines <- strsplit(trimmed, "\n", fixed = TRUE)[[1L]] + + # compute common indent + indent <- regexpr("[^[:space:]]", lines) + common <- min(setdiff(indent, -1L)) - leave + paste(substring(lines, common), collapse = "\n") + + } + + startswith <- function(string, prefix) { + substring(string, 1, nchar(prefix)) == prefix } bootstrap <- function(version, library) { + friendly <- renv_bootstrap_version_friendly(version) + section <- header(sprintf("Bootstrapping renv %s", friendly)) + catf(section) + # attempt to download renv - tarball <- tryCatch(renv_bootstrap_download(version), error = identity) - if (inherits(tarball, "error")) - stop("failed to download renv ", version) + catf("- Downloading renv ... ", appendLF = FALSE) + withCallingHandlers( + tarball <- renv_bootstrap_download(version), + error = function(err) { + catf("FAILED") + stop("failed to download:\n", conditionMessage(err)) + } + ) + catf("OK") + on.exit(unlink(tarball), add = TRUE) # now attempt to install - status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity) - if (inherits(status, "error")) - stop("failed to install renv ", version) + catf("- Installing renv ... ", appendLF = FALSE) + withCallingHandlers( + status <- renv_bootstrap_install(version, tarball, library), + error = function(err) { + catf("FAILED") + stop("failed to install:\n", conditionMessage(err)) + } + ) + catf("OK") + + # add empty line to break up bootstrapping from normal output + catf("") + return(invisible()) } renv_bootstrap_tests_running <- function() { @@ -83,28 +191,32 @@ local({ renv_bootstrap_repos <- function() { + # get CRAN repository + cran <- getOption("renv.repos.cran", "https://cloud.r-project.org") + # check for repos override repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) - if (!is.na(repos)) + if (!is.na(repos)) { + + # check for RSPM; if set, use a fallback repository for renv + rspm <- Sys.getenv("RSPM", unset = NA) + if (identical(rspm, repos)) + repos <- c(RSPM = rspm, CRAN = cran) + return(repos) + } + # check for lockfile repositories repos <- tryCatch(renv_bootstrap_repos_lockfile(), error = identity) if (!inherits(repos, "error") && length(repos)) return(repos) - # if we're testing, re-use the test repositories - if (renv_bootstrap_tests_running()) - return(getOption("renv.tests.repos")) - # retrieve current repos repos <- getOption("repos") # ensure @CRAN@ entries are resolved - repos[repos == "@CRAN@"] <- getOption( - "renv.repos.cran", - "https://cloud.r-project.org" - ) + repos[repos == "@CRAN@"] <- cran # add in renv.bootstrap.repos if set default <- c(FALLBACK = "https://cloud.r-project.org") @@ -143,33 +255,34 @@ local({ renv_bootstrap_download <- function(version) { - # if the renv version number has 4 components, assume it must - # be retrieved via github - nv <- numeric_version(version) - components <- unclass(nv)[[1]] - - # if this appears to be a development version of 'renv', we'll - # try to restore from github - dev <- length(components) == 4L - - # begin collecting different methods for finding renv - methods <- c( - renv_bootstrap_download_tarball, - if (dev) - renv_bootstrap_download_github - else c( - renv_bootstrap_download_cran_latest, - renv_bootstrap_download_cran_archive + sha <- attr(version, "sha", exact = TRUE) + + methods <- if (!is.null(sha)) { + + # attempting to bootstrap a development version of renv + c( + function() renv_bootstrap_download_tarball(sha), + function() renv_bootstrap_download_github(sha) ) - ) + + } else { + + # attempting to bootstrap a release version of renv + c( + function() renv_bootstrap_download_tarball(version), + function() renv_bootstrap_download_cran_latest(version), + function() renv_bootstrap_download_cran_archive(version) + ) + + } for (method in methods) { - path <- tryCatch(method(version), error = identity) + path <- tryCatch(method(), error = identity) if (is.character(path) && file.exists(path)) return(path) } - stop("failed to download renv ", version) + stop("All download methods failed") } @@ -185,43 +298,75 @@ local({ if (fixup) mode <- "w+b" - utils::download.file( + args <- list( url = url, destfile = destfile, mode = mode, quiet = TRUE ) + if ("headers" %in% names(formals(utils::download.file))) + args$headers <- renv_bootstrap_download_custom_headers(url) + + do.call(utils::download.file, args) + } - renv_bootstrap_download_cran_latest <- function(version) { + renv_bootstrap_download_custom_headers <- function(url) { - spec <- renv_bootstrap_download_cran_latest_find(version) + headers <- getOption("renv.download.headers") + if (is.null(headers)) + return(character()) + + if (!is.function(headers)) + stopf("'renv.download.headers' is not a function") - message("* Downloading renv ", version, " ... ", appendLF = FALSE) + headers <- headers(url) + if (length(headers) == 0L) + return(character()) + if (is.list(headers)) + headers <- unlist(headers, recursive = FALSE, use.names = TRUE) + + ok <- + is.character(headers) && + is.character(names(headers)) && + all(nzchar(names(headers))) + + if (!ok) + stop("invocation of 'renv.download.headers' did not return a named character vector") + + headers + + } + + renv_bootstrap_download_cran_latest <- function(version) { + + spec <- renv_bootstrap_download_cran_latest_find(version) type <- spec$type repos <- spec$repos - info <- tryCatch( - utils::download.packages( - pkgs = "renv", - destdir = tempdir(), - repos = repos, - type = type, - quiet = TRUE - ), + baseurl <- utils::contrib.url(repos = repos, type = type) + ext <- if (identical(type, "source")) + ".tar.gz" + else if (Sys.info()[["sysname"]] == "Windows") + ".zip" + else + ".tgz" + name <- sprintf("renv_%s%s", version, ext) + url <- paste(baseurl, name, sep = "/") + + destfile <- file.path(tempdir(), name) + status <- tryCatch( + renv_bootstrap_download_impl(url, destfile), condition = identity ) - if (inherits(info, "condition")) { - message("FAILED") + if (inherits(status, "condition")) return(FALSE) - } # report success and return - message("OK (downloaded ", type, ")") - info[1, 2] + destfile } @@ -277,8 +422,6 @@ local({ urls <- file.path(repos, "src/contrib/Archive/renv", name) destfile <- file.path(tempdir(), name) - message("* Downloading renv ", version, " ... ", appendLF = FALSE) - for (url in urls) { status <- tryCatch( @@ -286,14 +429,11 @@ local({ condition = identity ) - if (identical(status, 0L)) { - message("OK") + if (identical(status, 0L)) return(destfile) - } } - message("FAILED") return(FALSE) } @@ -307,8 +447,7 @@ local({ return() # allow directories - info <- file.info(tarball, extra_cols = FALSE) - if (identical(info$isdir, TRUE)) { + if (dir.exists(tarball)) { name <- sprintf("renv_%s.tar.gz", version) tarball <- file.path(tarball, name) } @@ -317,7 +456,7 @@ local({ if (!file.exists(tarball)) { # let the user know we weren't able to honour their request - fmt <- "* RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist." + fmt <- "- RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist." msg <- sprintf(fmt, tarball) warning(msg) @@ -326,10 +465,7 @@ local({ } - fmt <- "* Bootstrapping with tarball at path '%s'." - msg <- sprintf(fmt, tarball) - message(msg) - + catf("- Using local tarball '%s'.", tarball) tarball } @@ -356,8 +492,6 @@ local({ on.exit(do.call(base::options, saved), add = TRUE) } - message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE) - url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) name <- sprintf("renv_%s.tar.gz", version) destfile <- file.path(tempdir(), name) @@ -367,26 +501,105 @@ local({ condition = identity ) - if (!identical(status, 0L)) { - message("FAILED") + if (!identical(status, 0L)) return(FALSE) - } - message("OK") + renv_bootstrap_download_augment(destfile) + return(destfile) } + # Add Sha to DESCRIPTION. This is stop gap until #890, after which we + # can use renv::install() to fully capture metadata. + renv_bootstrap_download_augment <- function(destfile) { + sha <- renv_bootstrap_git_extract_sha1_tar(destfile) + if (is.null(sha)) { + return() + } + + # Untar + tempdir <- tempfile("renv-github-") + on.exit(unlink(tempdir, recursive = TRUE), add = TRUE) + untar(destfile, exdir = tempdir) + pkgdir <- dir(tempdir, full.names = TRUE)[[1]] + + # Modify description + desc_path <- file.path(pkgdir, "DESCRIPTION") + desc_lines <- readLines(desc_path) + remotes_fields <- c( + "RemoteType: github", + "RemoteHost: api.github.com", + "RemoteRepo: renv", + "RemoteUsername: rstudio", + "RemotePkgRef: rstudio/renv", + paste("RemoteRef: ", sha), + paste("RemoteSha: ", sha) + ) + writeLines(c(desc_lines[desc_lines != ""], remotes_fields), con = desc_path) + + # Re-tar + local({ + old <- setwd(tempdir) + on.exit(setwd(old), add = TRUE) + + tar(destfile, compression = "gzip") + }) + invisible() + } + + # Extract the commit hash from a git archive. Git archives include the SHA1 + # hash as the comment field of the tarball pax extended header + # (see https://www.kernel.org/pub/software/scm/git/docs/git-archive.html) + # For GitHub archives this should be the first header after the default one + # (512 byte) header. + renv_bootstrap_git_extract_sha1_tar <- function(bundle) { + + # open the bundle for reading + # We use gzcon for everything because (from ?gzcon) + # > Reading from a connection which does not supply a 'gzip' magic + # > header is equivalent to reading from the original connection + conn <- gzcon(file(bundle, open = "rb", raw = TRUE)) + on.exit(close(conn)) + + # The default pax header is 512 bytes long and the first pax extended header + # with the comment should be 51 bytes long + # `52 comment=` (11 chars) + 40 byte SHA1 hash + len <- 0x200 + 0x33 + res <- rawToChar(readBin(conn, "raw", n = len)[0x201:len]) + + if (grepl("^52 comment=", res)) { + sub("52 comment=", "", res) + } else { + NULL + } + } + renv_bootstrap_install <- function(version, tarball, library) { # attempt to install it into project library - message("* Installing renv ", version, " ... ", appendLF = FALSE) dir.create(library, showWarnings = FALSE, recursive = TRUE) + output <- renv_bootstrap_install_impl(library, tarball) + + # check for successful install + status <- attr(output, "status") + if (is.null(status) || identical(status, 0L)) + return(status) + + # an error occurred; report it + header <- "installation of renv failed" + lines <- paste(rep.int("=", nchar(header)), collapse = "") + text <- paste(c(header, lines, output), collapse = "\n") + stop(text) + + } + + renv_bootstrap_install_impl <- function(library, tarball) { # invoke using system2 so we can capture and report output bin <- R.home("bin") exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" - r <- file.path(bin, exe) + R <- file.path(bin, exe) args <- c( "--vanilla", "CMD", "INSTALL", "--no-multiarch", @@ -394,19 +607,7 @@ local({ shQuote(path.expand(tarball)) ) - output <- system2(r, args, stdout = TRUE, stderr = TRUE) - message("Done!") - - # check for successful install - status <- attr(output, "status") - if (is.numeric(status) && !identical(status, 0L)) { - header <- "Error installing renv:" - lines <- paste(rep.int("=", nchar(header)), collapse = "") - text <- c(header, lines, output) - writeLines(text, con = stderr()) - } - - status + system2(R, args, stdout = TRUE, stderr = TRUE) } @@ -447,6 +648,9 @@ local({ # if the user has requested an automatic prefix, generate it auto <- Sys.getenv("RENV_PATHS_PREFIX_AUTO", unset = NA) + if (is.na(auto) && getRversion() >= "4.4.0") + auto <- "TRUE" + if (auto %in% c("TRUE", "True", "true", "1")) return(renv_bootstrap_platform_prefix_auto()) @@ -616,34 +820,61 @@ local({ } - renv_bootstrap_validate_version <- function(version) { + renv_bootstrap_validate_version <- function(version, description = NULL) { + + # resolve description file + # + # avoid passing lib.loc to `packageDescription()` below, since R will + # use the loaded version of the package by default anyhow. note that + # this function should only be called after 'renv' is loaded + # https://github.com/rstudio/renv/issues/1625 + description <- description %||% packageDescription("renv") + + # check whether requested version 'version' matches loaded version of renv + sha <- attr(version, "sha", exact = TRUE) + valid <- if (!is.null(sha)) + renv_bootstrap_validate_version_dev(sha, description) + else + renv_bootstrap_validate_version_release(version, description) - loadedversion <- utils::packageDescription("renv", fields = "Version") - if (version == loadedversion) + if (valid) return(TRUE) - # assume four-component versions are from GitHub; three-component - # versions are from CRAN - components <- strsplit(loadedversion, "[.-]")[[1]] - remote <- if (length(components) == 4L) - paste("rstudio/renv", loadedversion, sep = "@") + # the loaded version of renv doesn't match the requested version; + # give the user instructions on how to proceed + dev <- identical(description[["RemoteType"]], "github") + remote <- if (dev) + paste("rstudio/renv", description[["RemoteSha"]], sep = "@") else - paste("renv", loadedversion, sep = "@") + paste("renv", description[["Version"]], sep = "@") - fmt <- paste( - "renv %1$s was loaded from project library, but this project is configured to use renv %2$s.", - "Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.", - "Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.", - sep = "\n" + # display both loaded version + sha if available + friendly <- renv_bootstrap_version_friendly( + version = description[["Version"]], + sha = if (dev) description[["RemoteSha"]] ) - msg <- sprintf(fmt, loadedversion, version, remote) - warning(msg, call. = FALSE) + fmt <- heredoc(" + renv %1$s was loaded from project library, but this project is configured to use renv %2$s. + - Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile. + - Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library. + ") + catf(fmt, friendly, renv_bootstrap_version_friendly(version), remote) FALSE } + renv_bootstrap_validate_version_dev <- function(version, description) { + expected <- description[["RemoteSha"]] + is.character(expected) && startswith(expected, version) + } + + renv_bootstrap_validate_version_release <- function(version, description) { + expected <- description[["Version"]] + is.character(expected) && identical(expected, version) + } + renv_bootstrap_hash_text <- function(text) { hashfile <- tempfile("renv-hash-") @@ -663,6 +894,12 @@ local({ # warn if the version of renv loaded does not match renv_bootstrap_validate_version(version) + # execute renv load hooks, if any + hooks <- getHook("renv::autoload") + for (hook in hooks) + if (is.function(hook)) + tryCatch(hook(), error = warnify) + # load the project renv::load(project) @@ -678,7 +915,7 @@ local({ return(profile) # check for a profile file (nothing to do if it doesn't exist) - path <- renv_bootstrap_paths_renv("profile", profile = FALSE) + path <- renv_bootstrap_paths_renv("profile", profile = FALSE, project = project) if (!file.exists(path)) return(NULL) @@ -802,12 +1039,78 @@ local({ } + renv_bootstrap_version_friendly <- function(version, shafmt = NULL, sha = NULL) { + sha <- sha %||% attr(version, "sha", exact = TRUE) + parts <- c(version, sprintf(shafmt %||% " [sha: %s]", substring(sha, 1L, 7L))) + paste(parts, collapse = "") + } + + renv_bootstrap_exec <- function(project, libpath, version) { + if (!renv_bootstrap_load(project, libpath, version)) + renv_bootstrap_run(version, libpath) + } + + renv_bootstrap_run <- function(version, libpath) { + + # perform bootstrap + bootstrap(version, libpath) + + # exit early if we're just testing bootstrap + if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) + return(TRUE) + + # try again to load + if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { + return(renv::load(project = getwd())) + } + + # failed to download or load renv; warn the user + msg <- c( + "Failed to find an renv installation: the project will not be loaded.", + "Use `renv::activate()` to re-initialize the project." + ) + + warning(paste(msg, collapse = "\n"), call. = FALSE) + + } renv_json_read <- function(file = NULL, text = NULL) { - text <- paste(text %||% read(file), collapse = "\n") + jlerr <- NULL + + # if jsonlite is loaded, use that instead + if ("jsonlite" %in% loadedNamespaces()) { + + json <- tryCatch(renv_json_read_jsonlite(file, text), error = identity) + if (!inherits(json, "error")) + return(json) + + jlerr <- json + + } + + # otherwise, fall back to the default JSON reader + json <- tryCatch(renv_json_read_default(file, text), error = identity) + if (!inherits(json, "error")) + return(json) + + # report an error + if (!is.null(jlerr)) + stop(jlerr) + else + stop(json) + + } + + renv_json_read_jsonlite <- function(file = NULL, text = NULL) { + text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") + jsonlite::fromJSON(txt = text, simplifyVector = FALSE) + } + + renv_json_read_default <- function(file = NULL, text = NULL) { # find strings in the JSON + text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") pattern <- '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' locs <- gregexpr(pattern, text, perl = TRUE)[[1]] @@ -838,8 +1141,9 @@ local({ # transform the JSON into something the R parser understands transformed <- replaced - transformed <- gsub("[[{]", "list(", transformed) - transformed <- gsub("[]}]", ")", transformed) + transformed <- gsub("{}", "`names<-`(list(), character())", transformed, fixed = TRUE) + transformed <- gsub("[[{]", "list(", transformed, perl = TRUE) + transformed <- gsub("[]}]", ")", transformed, perl = TRUE) transformed <- gsub(":", "=", transformed, fixed = TRUE) text <- paste(transformed, collapse = "\n") @@ -854,14 +1158,14 @@ local({ map <- as.list(map) # remap strings in object - remapped <- renv_json_remap(json, map) + remapped <- renv_json_read_remap(json, map) # evaluate eval(remapped, envir = baseenv()) } - renv_json_remap <- function(json, map) { + renv_json_read_remap <- function(json, map) { # fix names if (!is.null(names(json))) { @@ -888,7 +1192,7 @@ local({ # recurse if (is.recursive(json)) { for (i in seq_along(json)) { - json[i] <- list(renv_json_remap(json[[i]], map)) + json[i] <- list(renv_json_read_remap(json[[i]], map)) } } @@ -908,35 +1212,9 @@ local({ # construct full libpath libpath <- file.path(root, prefix) - # attempt to load - if (renv_bootstrap_load(project, libpath, version)) - return(TRUE) - - # load failed; inform user we're about to bootstrap - prefix <- paste("# Bootstrapping renv", version) - postfix <- paste(rep.int("-", 77L - nchar(prefix)), collapse = "") - header <- paste(prefix, postfix) - message(header) - - # perform bootstrap - bootstrap(version, libpath) - - # exit early if we're just testing bootstrap - if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) - return(TRUE) - - # try again to load - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { - message("* Successfully installed and loaded renv ", version, ".") - return(renv::load()) - } - - # failed to download or load renv; warn the user - msg <- c( - "Failed to find an renv installation: the project will not be loaded.", - "Use `renv::activate()` to re-initialize the project." - ) + # run bootstrap code + renv_bootstrap_exec(project, libpath, version) - warning(paste(msg, collapse = "\n"), call. = FALSE) + invisible() }) diff --git a/renv/settings.json b/renv/settings.json new file mode 100644 index 0000000..2472d63 --- /dev/null +++ b/renv/settings.json @@ -0,0 +1,19 @@ +{ + "bioconductor.version": [], + "external.libraries": [], + "ignored.packages": [], + "package.dependency.fields": [ + "Imports", + "Depends", + "LinkingTo" + ], + "ppm.enabled": null, + "ppm.ignored.urls": [], + "r.version": [], + "snapshot.type": "implicit", + "use.cache": true, + "vcs.ignore.cellar": true, + "vcs.ignore.library": true, + "vcs.ignore.local": true, + "vcs.manage.ignores": true +}