rirods vs iCommands

Mariana Montes

2024-03-15

This article is meant for iRODS users familiar with iCommands, the command-line interface to iRODS. While {rirods} functions are based on iCommands, not all iCommands are covered and some functionality may differ. The article also compares the bash calls to the R calls in case the reader is not so familiar with R syntax.

The table below lists the main functions available in {rirods} and their counterparts in iCommands.

{rirods} iCommands
icd() icd
ipwd() ipwd
ils() ils
iget(), ireadRDS() iget
iput(), isaveRDS() iput
imeta() imeta
iquery() iquest
imkdir() imkdir
irm() irm

A general note is that in iCommands the -h argument provides the documentation for a certain command (e.g. icd -h), whereas in R this is achieved by preceding the name of the function with ? (e.g. ?icd). Moreover, the verbose boolean argument in most of {rirods} commands is used to print information about the HTTP request and response (and is by default FALSE), which is not a behaviour relevant to iCommands.

Working directory and collections

The iCommand ipwd and its {rirods} counterpart ipwd() work exactly the same, providing the path to the current working directory. The case of icd() is different; unlike icd, which returns the “/zone/home” directory if no argument is provided, icd() needs an argument with the path for a new working directory. icd("/tempZone/home") will take us to "/tempZone/home" like icd might, but icd() with no arguments will throw an error.

When it comes to listing the contents of a collection, both ils and ils() can be given a path, and if they are not, they list the contents of the working directory. Permissions can be shown by ils with the -A argument and by ils() by providing permissions=TRUE, although the latter does not return information about inheritance1. The time that the item was last modified and the size of data objects is shown by ils -l and by ils(stats=TRUE).

ils() # ils
ils("some_collection") # ils some_collection
ils("some_collection", stat = TRUE) # ils -l some_collection
ils("some_collection", permissions = TRUE) # ils -A some_collection
ils(permissions=TRUE, stat = TRUE) # ils -Al

A crucial difference between ils and ils() is that ils(metadata=TRUE) is used to print the metadata information of each element listed, whereas iCommands only provides metadata information of one element at a time by calling imeta ls on it. At the moment, {rirods} does not offer any fast way of restricting the metadata to a specific item, although the custom function filter_ils() shown below could be used to achieve this result.

filter_ils <- function(pattern, ils_output = ils()) {
  stopifnot(inherits(ils_output, "irods_df"))
  ils_df <- as.data.frame(ils_output)
  if (length(pattern) == 1) {
    filtered <- ils_df[grepl(pattern, ils_df$logical_path), ]
  } else {
    filtered <- ils_df[basename(ils_df$logical_path) %in% pattern, ]
  }
  rirods:::new_irods_df(filtered)
}
my_files <- ils("some_collection", metadata = TRUE)
my_files
filter_ils("random", my_files) # imeta ls -d some_collection/random_numbers.rds

Creating and deleting collections or data objects

With iCommands we can create new collections and data objects with imkdir and itouch respectively. The former is matched in {rirods} by imkdir(), but the latter is not covered by the R package yet.

Both in iCommands and in {rirods}, imkdir() requires a path and has an argument to request creating the parent collections:

imkdir("new_collection") # imkdir new_collection
ils()

# imkdir -p another_collection/subcollection
imkdir("another_collection/subcollection", create_parent_collections = TRUE)

ils()
ils("another_collection")

Removing data objects and collections can be achieved by irm in iCommands and irm() in {rirods}, and both functions have a force and recursive arguments:

irm("200numbers.rds", force = FALSE) # irm 200numbers.rds
ils("/tempZone/trash/home/rods")

irm("another_collection", force = TRUE, recursive = TRUE) # irm -rf another_collection
iquery("SELECT COLL_NAME WHERE COLL_NAME LIKE '%_collection'")

Getting and putting data

In order to transfer data between a local system and iRODS, the main iCommands are iput and iget, which have iput() and iget() as {rirods} counterparts. The {rirods} functions are much more restricted in that they don’t really offer the variety of arguments that the iCommands do, but only options related to the HTTP requests. Moreover, they require the user to provide both the local and logical paths explicitly, whereas the iCommands reuse the source path by default. In other words, while iput myfile.txt will take a local file “myfile.txt” and store it in the iRODS working directory as “myfile.txt”, iput("myfile.txt") will throw an error; iput("myfile.txt", "myfile.txt") is the correct syntax to achieve the desired effect:

{rirods} iCommands Result
iget("myfile.txt", "myfile.txt") iget myfile.txt “myfile.txt” is copied from iRODS to local as “myfile.txt”
iget("myfile.txt", "another_path/filename.txt") iget myfile.txt another_path/filename.txt “myfile.txt” is copied from iRODS to local as “filename.txt” in “another_path”
iput("data.csv", "data.csv") iput data.csv “data.csv” is copied from local to iRODS as “data.csv”
iput("data.csv", "data2.csv") iput data.csv data2.csv “data.csv” is copied from local to iRODS as “data2.csv”

Next to these functions, {rirods} provides two functions to store R objects directly into iRODS or read RDS files directly from iRODS: isaveRDS() and ireadRDS(). There is no counterpart in iCommands. To achieve the same effect as isaveRDS(), a user would first have to save their object with saveRDS(), then send it to iRODS with iput and finally remove it with irm -f; in the same vein, the effect of ireadRDS() would be achieved by retrieving the file with iget, reading it with readRDS() and then removing it from the local space. Read more about this in vignette("local-irods").

Metadata and querying

The {rirods} imeta() function covers two of the main functionalities of the imeta iCommand: adding and removing metadata from a data object or collection. This function has three main arguments: the logical path of the data object or collection on which to add the metadata, the entity type (e.g. “data_object”, the default, or “collection”) and a list of operations, in which it is specified whether a certain AVU should be added or removed.

icd("some_collection")
ils(metadata=TRUE)

# imeta add -C subcollection foo bar baz
imeta("subcollection",
      operations = list(
        list(operation="add", attribute="foo", value="bar", units="baz")
        )
      )

# imeta rm -d random_numbers.rds distribution normal
imeta("random_numbers.rds",
      operations = list(
        list(operation="remove", attribute="distribution", value="normal")
      ))

ils(metadata=TRUE)

In order to “modify” an AVU with {rirods}, we would have to remove it and add its replacement. This also illustrates how we can add/remove several AVUs in one imeta() call, which would not be possible with imeta2.

# imeta mod -d random_numbers.rds length 100 items u:elements
imeta("random_numbers.rds",
      operations = list(
        list(operation="remove", attribute="length", value="100", units="items"),
        list(operation="add", attribute="length", value="100", units="elements")
      ))
ils(metadata=TRUE)

As mentioned before, whereas the iCommand imeta ls is used to list the metadata of an item, ils(metadata=TRUE) is used in {rirods} instead.

Finally, the {rirods} equivalent of iCommand iquest is iquery(), with the same GenQuery expression as main argument and a few compatible arguments. Given a query variable such as “SELECT DATA_NAME, DATA_CHECKSUM WHERE COLL_NAME LIKE ‘/tempZone/home/rods%’”:

{rirods} iCommands
iquery(query) iquest "$query"
iquery(query, case_sensitive = FALSE) iquest uppercase "$query"
iquery(query, distinct = FALSE) iquest no-distinct "$query"

To learn more about imeta() and iquery(), see vignette("metadata").


  1. At the moment there is no functionality in {rirods} to set permissions.↩︎

  2. This is similar to the behavior of atomic operations in the Python client.↩︎