path_real() mangles paths starting with ~ on Windows
On Windows, I get:
fs::path_real("~/R/dev")
#> C:/Users/mikko/AppData/Local/Temp/Rtmpa8cpqi/reprex37584fd22289/Users/mikko/R/dev
I would expect to get:
file.path(path.expand("~"), "R", "dev")
#> [1] "C:/Users/mikko/Documents/R/dev"
Created on 2019-09-28 by the reprex package (v0.3.0)
I ran into this as many usethis functions were failing due to path errors. Maybe related to #206?
Session info
devtools::session_info()
#> - Session info ----------------------------------------------------------
#> setting value
#> version R version 3.6.1 (2019-07-05)
#> os Windows 10 x64
#> system x86_64, mingw32
#> ui RTerm
#> language (EN)
#> collate English_United States.1252
#> ctype English_United States.1252
#> tz Europe/Helsinki
#> date 2019-09-28
#>
#> - Packages --------------------------------------------------------------
#> package * version date lib source
#> assertthat 0.2.1 2019-03-21 [1] CRAN (R 3.6.0)
#> backports 1.1.4 2019-04-10 [1] CRAN (R 3.6.0)
#> callr 3.3.0 2019-07-04 [1] CRAN (R 3.6.1)
#> cli 1.1.0 2019-03-19 [1] CRAN (R 3.6.0)
#> crayon 1.3.4 2017-09-16 [1] CRAN (R 3.6.0)
#> desc 1.2.0 2018-05-01 [1] CRAN (R 3.6.0)
#> devtools 2.1.0 2019-07-06 [1] CRAN (R 3.6.1)
#> digest 0.6.20 2019-07-04 [1] CRAN (R 3.6.1)
#> evaluate 0.14 2019-05-28 [1] CRAN (R 3.6.0)
#> fs 1.3.1.9000 2019-09-28 [1] Github (r-lib/fs@380685c)
#> glue 1.3.1 2019-03-12 [1] CRAN (R 3.6.0)
#> highr 0.8 2019-03-20 [1] CRAN (R 3.6.0)
#> htmltools 0.3.6 2017-04-28 [1] CRAN (R 3.6.0)
#> knitr 1.23 2019-05-18 [1] CRAN (R 3.6.0)
#> magrittr 1.5 2014-11-22 [1] CRAN (R 3.6.0)
#> memoise 1.1.0 2017-04-21 [1] CRAN (R 3.6.0)
#> pkgbuild 1.0.3 2019-03-20 [1] CRAN (R 3.6.0)
#> pkgload 1.0.2 2018-10-29 [1] CRAN (R 3.6.0)
#> prettyunits 1.0.2 2015-07-13 [1] CRAN (R 3.6.0)
#> processx 3.4.0 2019-07-03 [1] CRAN (R 3.6.1)
#> ps 1.3.0 2018-12-21 [1] CRAN (R 3.6.0)
#> R6 2.4.0 2019-02-14 [1] CRAN (R 3.6.0)
#> Rcpp 1.0.2 2019-07-25 [1] CRAN (R 3.6.1)
#> remotes 2.1.0 2019-06-24 [1] CRAN (R 3.6.0)
#> rlang 0.4.0 2019-06-25 [1] CRAN (R 3.6.0)
#> rmarkdown 1.13 2019-05-22 [1] CRAN (R 3.6.0)
#> rprojroot 1.3-2 2018-01-03 [1] CRAN (R 3.6.0)
#> sessioninfo 1.1.1 2018-11-05 [1] CRAN (R 3.6.0)
#> stringi 1.4.3 2019-03-12 [1] CRAN (R 3.6.0)
#> stringr 1.4.0 2019-02-10 [1] CRAN (R 3.6.0)
#> testthat 2.1.1 2019-04-23 [1] CRAN (R 3.6.0)
#> usethis 1.5.1.9000 2019-09-28 [1] Github (r-lib/usethis@a2342b8)
#> withr 2.1.2 2018-03-15 [1] CRAN (R 3.6.0)
#> xfun 0.8 2019-06-25 [1] CRAN (R 3.6.0)
#> yaml 2.2.0 2018-07-25 [1] CRAN (R 3.6.0)
#>
#> [1] C:/Users/mikko/Documents/R/win-library/3.6
#> [2] C:/Program Files/R/R-3.6.1/library
One thing to know with fs is that it handles ~ differently than R base on windows. It uses USERPROFILE env var as home. See ?fs::path_expand
This is why you have fs::path_expand_r also to get the R default behavior if needed
fs::path_expand("~/R/dev")
#> C:/Users/chris/R/dev
fs::path_expand_r("~/R/dev")
#> C:/Users/chris/Documents/R/dev
fs::path_real uses fs::path_expand (see help page and source code). So on windows I think it explains what you don't get the expected result with Documents in the path.
What I can't explain is why fs::path_real uses the temp directory used by reprex when creating the canonical path...
In fact, it uses the current working directory and add the expanded path. 🤔
library(fs)
directory <- dir_create(file_temp())
directory
#> C:/Users/chris/AppData/Local/Temp/Rtmp4Oe4ko/file5b58569770e8
setwd(directory)
path_expand("~/R/dev")
#> C:/Users/chris/R/dev
path_real("~/R/dev")
#> C:/Users/chris/AppData/Local/Temp/Rtmp4Oe4ko/file5b58569770e8/Users/chris/R/dev
Created on 2019-09-28 by the reprex package (v0.3.0)
I am not sure if it is intended or not.
Hope it helps.
Thanks, I hadn't realized the difference in path_expand(). I think this means that my problem (which originated with usethis::use_test()) would not be fixed even if path_real() didn't expand in the working directory.
Yeah I can reproduce this on Windows. If someone has written a path with a leading ~ on Windows, based on R's definition of home directory (so Documents/), the initial path_expand() in path_real() creates a nonexistent path. Then the logic for "partially existing" paths gets invoked, leading to the peculiar double expansion described above.
This appears to be part of the problem. fs:::realize_("C:") returns the absolute path to current working directory.
fs:::realize_("C:")
#> [1] "C:\\Users\\jenny\\AppData\\Local\\Temp\\RtmporMOb5\\reprex1d345ab82c19"
Created on 2019-09-30 by the reprex package (v0.3.0.9000)
Related to this issue, if the path does not exist, path_real() inserts the value of the current working directory:
packageVersion("fs")
#> [1] '1.3.1.9000'
fs::path_real("C:/Users/")
#> C:/Users
fs::path_real("C:/Users/non-existent")
#> C:/Users/john/AppData/Local/Temp/Rtmp6jGsyB/reprex4f867412f09/Users/non-existent
Created on 2019-10-08 by the reprex package (v0.3.0.9000)
This behavior was introduced in fs version 1.2.7:
packageVersion("fs")
#> [1] '1.2.7'
fs::path_real("C:/Users/")
#> C:/Users
fs::path_real("C:/Users/non-existent")
#> C:/Users/john/AppData/Local/Temp/Rtmp4aK0dQ/reprex371838e373c/Users/non-existent
Created on 2019-10-08 by the reprex package (v0.3.0.9000)
In fs 1.2.6, path_real() threw an error if the file path did not exist:
packageVersion("fs")
#> [1] '1.2.6'
fs::path_real("C:/Users/")
#> C:/Users
fs::path_real("C:/Users/non-existent")
#> Error: [ENOENT] Failed to realize 'C:/Users/non-existent': no such file or directory
Created on 2019-10-08 by the reprex package (v0.3.0.9000)