osfr

First, it is necessary to get an API key from OSF. Do this by heading to your OSF project, your user settings, and selecting “create new key”.

Keep that key safe, this is very important, ie don’t share it with anyone.

That being said, we do need to store it somewhere so that osfr can access it. The most sensible place, and where osfr will look for it, is in a file called .Renviron in your home folder. We will first check if a .Renviron file exists already – if it does, we’ll add our key to it – if it doesn’t, we’ll create it, and then add our key to it.

To do this, we’ll use the ‘Terminal’ adjacent to the R Console.

# list all files in the home directory (~ is short for home, you can also try $HOME if ~ doesn't work)
# including hidden files (the -a does this)
# and then with grep, filter that list for the file name of interest
ls -a ~/ | grep ".Renviron"

If you’re presented with a blank line, .Renviron doesn’t exist. So let’s create it.

touch ~/.Renviron

And we’ll write our API token or key to the file, copying and pasting your key after the = sign below.

echo "OSF_PAT=" >> ~./Renviron

To validate this worked, you can run

cat ~./Renviron

You will need to restart R before this file and / or it’s new information is accessible. To do this, go to Session > Restart R from the RStudio menu.

Next, we install, if not already installed, and load, osfr

install.packages("osfr")
library(osfr)
## Automatically registered OSF personal access token

You should get the above output, indicating that osfr has successfully found your API token so that you can authenticate.

Accessing your project

Next, we download the metadata associated with our OSF project. You’ll need the url from the landing page of your OSF project.

jumpstart_project <- osf_retrieve_node("https://osf.io/uha5g/")

Then, we look at the list of files in our project:

js_files <- osf_ls_files(jumpstart_project)
js_files
## # A tibble: 9 × 3
##   name        id                       meta            
##   <chr>       <chr>                    <list>          
## 1 scripts     68220a2fc6762f78ebc0d856 <named list [3]>
## 2 data        68220a2fc6762f78ebc0d857 <named list [3]>
## 3 docs        68220a2fc6762f78ebc0d859 <named list [3]>
## 4 resources   68220a30c6762f78ebc0d860 <named list [3]>
## 5 tmp         68220a30c6762f78ebc0d86b <named list [3]>
## 6 README.md   68220a30c6762f78ebc0d86c <named list [3]>
## 7 outputs     68220a30c6762f78ebc0d86d <named list [3]>
## 8 license.txt 68220a30c6762f78ebc0d86e <named list [3]>
## 9 readme.md   68260dc6bbec12fd859c4265 <named list [3]>

A small caveat here, this works more easily with files than directories, so we’ll simply explore this with a single file, like the README.md file.

The meta column is a list of metadata associate with each file – we need to access the unique id of the file we want to download before we can download it. This is the same 5 digit alphanumeric code that we would see if we loaded the file for viewing within OSF. So, you could access it that way too.

readmeFile <- js_files$meta[[6]]$attributes$guid
readmeFile
## [1] "ystfh"

We then download it. We need to resolve how to handle conflicts, and here, I’m simply going to elect to overwrite any existing file with the same name, as this is my first ‘pull’.

osf_retrieve_file(readmeFile) |>
  osf_download(conflicts = "overwrite")

Since this is a markdown file, it can be opened and edited directly in RStudio. Once you’re done for the day, we can send it back to OSF and overwrite the one sitting on OSF servers.

osf_upload(jumpstart_project,
           "README.md",
           conflicts = "overwrite")

As long as you don’t change your file names, the unique ID of the files never changes. So, once you know what you need to routinely back up, you can get creative in automating this process using only osf_upload() to overwrite what’s on OSF servers.

While OSF with provide access to the historical versions of these overwrites that you are performing, osfr is not a version control system, that is to say, it does not look for changes in files, it does not compare dates on files, etc, it simply completely overwrites.

LS0tCnRpdGxlOiAib3NmciIKcGFnZXRpdGxlOiAib3NmciIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cgIyBhbGxvd3MgdG9nZ2xpbmcgb2Ygc2hvd2luZyBhbmQgaGlkaW5nIGNvZGUuIFJlbW92ZSBpZiBub3QgdXNpbmcgY29kZS4KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgIyBhbGxvd3MgdGhlIHVzZXIgdG8gZG93bmxvYWQgdGhlIHNvdXJjZSAuUm1kIGZpbGUuIFJlbW92ZSBpZiBub3QgdXNpbmcgY29kZS4KICAgIGluY2x1ZGVzOgogICAgICBhZnRlcl9ib2R5OiBmb290ZXIuaHRtbCAjIGluY2x1ZGUgYSBjdXN0b20gZm9vdGVyLgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQotLS0KCiMjIG9zZnIKCkZpcnN0LCBpdCBpcyBuZWNlc3NhcnkgdG8gZ2V0IGFuIEFQSSBrZXkgZnJvbSBPU0YuIERvIHRoaXMgYnkgaGVhZGluZyB0byB5b3VyIE9TRiBwcm9qZWN0LCB5b3VyIHVzZXIgc2V0dGluZ3MsIGFuZCBzZWxlY3RpbmcgImNyZWF0ZSBuZXcga2V5Ii4KCiFbXShpbWFnZXMvb3NmL29zZkFQSXRva2VuLmdpZikKCktlZXAgdGhhdCBrZXkgc2FmZSwgdGhpcyBpcyB2ZXJ5IGltcG9ydGFudCwgaWUgZG9uJ3Qgc2hhcmUgaXQgd2l0aCBhbnlvbmUuCgpUaGF0IGJlaW5nIHNhaWQsIHdlIGRvIG5lZWQgdG8gc3RvcmUgaXQgc29tZXdoZXJlIHNvIHRoYXQgYG9zZnJgIGNhbiBhY2Nlc3MgaXQuIFRoZSBtb3N0IHNlbnNpYmxlIHBsYWNlLCBhbmQgd2hlcmUgYG9zZnJgIHdpbGwgbG9vayBmb3IgaXQsIGlzIGluIGEgZmlsZSBjYWxsZWQgYC5SZW52aXJvbmAgaW4geW91ciBob21lIGZvbGRlci4gV2Ugd2lsbCBmaXJzdCBjaGVjayBpZiBhIGAuUmVudmlyb25gIGZpbGUgZXhpc3RzIGFscmVhZHkgLS0gaWYgaXQgZG9lcywgd2UnbGwgYWRkIG91ciBrZXkgdG8gaXQgLS0gaWYgaXQgZG9lc24ndCwgd2UnbGwgY3JlYXRlIGl0LCBhbmQgdGhlbiBhZGQgb3VyIGtleSB0byBpdC4KClRvIGRvIHRoaXMsIHdlJ2xsIHVzZSB0aGUgJ1Rlcm1pbmFsJyBhZGphY2VudCB0byB0aGUgUiBDb25zb2xlLgoKYGBge2Jhc2gsIGV2YWwgPSBGQUxTRX0KIyBsaXN0IGFsbCBmaWxlcyBpbiB0aGUgaG9tZSBkaXJlY3RvcnkgKH4gaXMgc2hvcnQgZm9yIGhvbWUsIHlvdSBjYW4gYWxzbyB0cnkgJEhPTUUgaWYgfiBkb2Vzbid0IHdvcmspCiMgaW5jbHVkaW5nIGhpZGRlbiBmaWxlcyAodGhlIC1hIGRvZXMgdGhpcykKIyBhbmQgdGhlbiB3aXRoIGdyZXAsIGZpbHRlciB0aGF0IGxpc3QgZm9yIHRoZSBmaWxlIG5hbWUgb2YgaW50ZXJlc3QKbHMgLWEgfi8gfCBncmVwICIuUmVudmlyb24iCmBgYAoKSWYgeW91J3JlIHByZXNlbnRlZCB3aXRoIGEgYmxhbmsgbGluZSwgYC5SZW52aXJvbmAgZG9lc24ndCBleGlzdC4gU28gbGV0J3MgY3JlYXRlIGl0LgoKYGBge2Jhc2gsIGV2YWwgPSBGQUxTRX0KdG91Y2ggfi8uUmVudmlyb24KYGBgCgpBbmQgd2UnbGwgd3JpdGUgb3VyIEFQSSB0b2tlbiBvciBrZXkgdG8gdGhlIGZpbGUsIGNvcHlpbmcgYW5kIHBhc3RpbmcgeW91ciBrZXkgYWZ0ZXIgdGhlIGA9YCBzaWduIGJlbG93LgoKYGBge2Jhc2gsIGV2YWwgPSBGQUxTRX0KZWNobyAiT1NGX1BBVD0iID4+IH4uL1JlbnZpcm9uCmBgYAoKVG8gdmFsaWRhdGUgdGhpcyB3b3JrZWQsIHlvdSBjYW4gcnVuCgpgYGB7YmFzaCwgZXZhbCA9IEZBTFNFfQpjYXQgfi4vUmVudmlyb24KYGBgCgpZb3Ugd2lsbCBuZWVkIHRvIHJlc3RhcnQgUiBiZWZvcmUgdGhpcyBmaWxlIGFuZCAvIG9yIGl0J3MgbmV3IGluZm9ybWF0aW9uIGlzIGFjY2Vzc2libGUuIFRvIGRvIHRoaXMsIGdvIHRvIGBTZXNzaW9uID4gUmVzdGFydCBSYCBmcm9tIHRoZSBSU3R1ZGlvIG1lbnUuCgpOZXh0LCB3ZSBpbnN0YWxsLCBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQsIGFuZCBsb2FkLCBgb3NmcmAKCmBgYHtyLCBldmFsID0gRkFMU0V9Cmluc3RhbGwucGFja2FnZXMoIm9zZnIiKQpsaWJyYXJ5KG9zZnIpCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRX0KbGlicmFyeShvc2ZyKQpgYGAKCllvdSBzaG91bGQgZ2V0IHRoZSBhYm92ZSBvdXRwdXQsIGluZGljYXRpbmcgdGhhdCBgb3NmcmAgaGFzIHN1Y2Nlc3NmdWxseSBmb3VuZCB5b3VyIEFQSSB0b2tlbiBzbyB0aGF0IHlvdSBjYW4gYXV0aGVudGljYXRlLgoKIyMgQWNjZXNzaW5nIHlvdXIgcHJvamVjdAoKTmV4dCwgd2UgZG93bmxvYWQgdGhlIG1ldGFkYXRhIGFzc29jaWF0ZWQgd2l0aCBvdXIgT1NGIHByb2plY3QuIFlvdSdsbCBuZWVkIHRoZSB1cmwgZnJvbSB0aGUgbGFuZGluZyBwYWdlIG9mIHlvdXIgT1NGIHByb2plY3QuCgpgYGB7cn0KanVtcHN0YXJ0X3Byb2plY3QgPC0gb3NmX3JldHJpZXZlX25vZGUoImh0dHBzOi8vb3NmLmlvL3VoYTVnLyIpCmBgYAoKVGhlbiwgd2UgbG9vayBhdCB0aGUgbGlzdCBvZiBmaWxlcyBpbiBvdXIgcHJvamVjdDoKCmBgYHtyfQpqc19maWxlcyA8LSBvc2ZfbHNfZmlsZXMoanVtcHN0YXJ0X3Byb2plY3QpCmpzX2ZpbGVzCmBgYAoKQSBzbWFsbCBjYXZlYXQgaGVyZSwgdGhpcyB3b3JrcyBtb3JlIGVhc2lseSB3aXRoIGZpbGVzIHRoYW4gZGlyZWN0b3JpZXMsIHNvIHdlJ2xsIHNpbXBseSBleHBsb3JlIHRoaXMgd2l0aCBhIHNpbmdsZSBmaWxlLCBsaWtlIHRoZSBSRUFETUUubWQgZmlsZS4KClRoZSBgbWV0YWAgY29sdW1uIGlzIGEgbGlzdCBvZiBtZXRhZGF0YSBhc3NvY2lhdGUgd2l0aCBlYWNoIGZpbGUgLS0gd2UgbmVlZCB0byBhY2Nlc3MgdGhlIHVuaXF1ZSBpZCBvZiB0aGUgZmlsZSB3ZSB3YW50IHRvIGRvd25sb2FkIGJlZm9yZSB3ZSBjYW4gZG93bmxvYWQgaXQuIFRoaXMgaXMgdGhlIHNhbWUgNSBkaWdpdCBhbHBoYW51bWVyaWMgY29kZSB0aGF0IHdlIHdvdWxkIHNlZSBpZiB3ZSBsb2FkZWQgdGhlIGZpbGUgZm9yIHZpZXdpbmcgd2l0aGluIE9TRi4gU28sIHlvdSBjb3VsZCBhY2Nlc3MgaXQgdGhhdCB3YXkgdG9vLgoKYGBge3J9CnJlYWRtZUZpbGUgPC0ganNfZmlsZXMkbWV0YVtbNl1dJGF0dHJpYnV0ZXMkZ3VpZApyZWFkbWVGaWxlCmBgYAoKV2UgdGhlbiBkb3dubG9hZCBpdC4gV2UgbmVlZCB0byByZXNvbHZlIGhvdyB0byBoYW5kbGUgY29uZmxpY3RzLCBhbmQgaGVyZSwgSSdtIHNpbXBseSBnb2luZyB0byBlbGVjdCB0byBvdmVyd3JpdGUgYW55IGV4aXN0aW5nIGZpbGUgd2l0aCB0aGUgc2FtZSBuYW1lLCBhcyB0aGlzIGlzIG15IGZpcnN0ICdwdWxsJy4KCmBgYHtyLCBldmFsID0gRkFMU0V9Cm9zZl9yZXRyaWV2ZV9maWxlKHJlYWRtZUZpbGUpIHw+CiAgb3NmX2Rvd25sb2FkKGNvbmZsaWN0cyA9ICJvdmVyd3JpdGUiKQpgYGAKClNpbmNlIHRoaXMgaXMgYSBtYXJrZG93biBmaWxlLCBpdCBjYW4gYmUgb3BlbmVkIGFuZCBlZGl0ZWQgZGlyZWN0bHkgaW4gUlN0dWRpby4gT25jZSB5b3UncmUgZG9uZSBmb3IgdGhlIGRheSwgd2UgY2FuIHNlbmQgaXQgYmFjayB0byBPU0YgYW5kIG92ZXJ3cml0ZSB0aGUgb25lIHNpdHRpbmcgb24gT1NGIHNlcnZlcnMuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpvc2ZfdXBsb2FkKGp1bXBzdGFydF9wcm9qZWN0LAogICAgICAgICAgICJSRUFETUUubWQiLAogICAgICAgICAgIGNvbmZsaWN0cyA9ICJvdmVyd3JpdGUiKQpgYGAKCkFzIGxvbmcgYXMgeW91IGRvbid0IGNoYW5nZSB5b3VyIGZpbGUgbmFtZXMsIHRoZSB1bmlxdWUgSUQgb2YgdGhlIGZpbGVzIG5ldmVyIGNoYW5nZXMuIFNvLCBvbmNlIHlvdSBrbm93IHdoYXQgeW91IG5lZWQgdG8gcm91dGluZWx5IGJhY2sgdXAsIHlvdSBjYW4gZ2V0IGNyZWF0aXZlIGluIGF1dG9tYXRpbmcgdGhpcyBwcm9jZXNzIHVzaW5nIG9ubHkgYG9zZl91cGxvYWQoKWAgdG8gb3ZlcndyaXRlIHdoYXQncyBvbiBPU0Ygc2VydmVycy4KCjo6Om5vdGUKV2hpbGUgT1NGIHdpdGggcHJvdmlkZSBhY2Nlc3MgdG8gdGhlIGhpc3RvcmljYWwgdmVyc2lvbnMgb2YgdGhlc2Ugb3ZlcndyaXRlcyB0aGF0IHlvdSBhcmUgcGVyZm9ybWluZywgYG9zZnJgIGlzIG5vdCBhIHZlcnNpb24gY29udHJvbCBzeXN0ZW0sIHRoYXQgaXMgdG8gc2F5LCBpdCBkb2VzIG5vdCBsb29rIGZvciBjaGFuZ2VzIGluIGZpbGVzLCBpdCBkb2VzIG5vdCBjb21wYXJlIGRhdGVzIG9uIGZpbGVzLCBldGMsIGl0IHNpbXBseSBjb21wbGV0ZWx5IG92ZXJ3cml0ZXMuCjo6OgoKCgoKCgoK