1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: Apache-2.0
5 getAPIDocument <- function(){
6 url <- "https://jutro.arvadosapi.com/discovery/v1/apis/arvados/v1/rest"
7 serverResponse <- httr::RETRY("GET", url = url)
9 httr::content(serverResponse, as = "parsed", type = "application/json")
14 #' Autogenerate classes to interact with Arvados from the Arvados discovery document.
17 generateAPI <- function()
19 #TODO: Consider passing discovery document URL as parameter.
20 #TODO: Consider passing location where to create new files.
21 discoveryDocument <- getAPIDocument()
23 methodResources <- discoveryDocument$resources
25 # Don't emit deprecated APIs
26 methodResources <- methodResources[!(names(methodResources) %in% c("jobs", "job_tasks", "pipeline_templates", "pipeline_instances",
27 "keep_disks", "nodes", "humans", "traits", "specimens"))]
28 resourceNames <- names(methodResources)
30 methodDoc <- genMethodsDoc(methodResources, resourceNames)
31 classDoc <- genAPIClassDoc(methodResources, resourceNames)
32 arvadosAPIHeader <- genAPIClassHeader()
33 arvadosProjectMethods <- genProjectMethods()
34 arvadosClassMethods <- genClassContent(methodResources, resourceNames)
35 arvadosAPIFooter <- genAPIClassFooter()
37 arvadosClass <- c(methodDoc,
40 arvadosProjectMethods,
44 fileConn <- file("./R/Arvados.R", "w")
46 "# Copyright (C) The Arvados Authors. All rights reserved.",
48 "# SPDX-License-Identifier: Apache-2.0", ""), fileConn)
49 writeLines(unlist(arvadosClass), fileConn)
54 genAPIClassHeader <- function()
56 c("Arvados <- R6::R6Class(",
62 "\t\tinitialize = function(authToken = NULL, hostName = NULL, numRetries = 0)",
64 "\t\t\tif(!is.null(hostName))",
65 "\t\t\t\tSys.setenv(ARVADOS_API_HOST = hostName)",
67 "\t\t\tif(!is.null(authToken))",
68 "\t\t\t\tSys.setenv(ARVADOS_API_TOKEN = authToken)",
70 "\t\t\thostName <- Sys.getenv(\"ARVADOS_API_HOST\")",
71 "\t\t\ttoken <- Sys.getenv(\"ARVADOS_API_TOKEN\")",
73 "\t\t\tif(hostName == \"\" | token == \"\")",
74 "\t\t\t\tstop(paste(\"Please provide host name and authentification token\",",
75 "\t\t\t\t\t\t \"or set ARVADOS_API_HOST and ARVADOS_API_TOKEN\",",
76 "\t\t\t\t\t\t \"environment variables.\"))",
78 "\t\t\tprivate$token <- token",
79 "\t\t\tprivate$host <- paste0(\"https://\", hostName, \"/arvados/v1/\")",
80 "\t\t\tprivate$numRetries <- numRetries",
81 "\t\t\tprivate$REST <- RESTService$new(token, hostName,",
82 "\t\t\t HttpRequest$new(), HttpParser$new(),",
88 genProjectMethods <- function()
90 c("\t\tprojects.get = function(uuid)",
92 "\t\t\tself$groups.get(uuid)",
95 "\t\tprojects.create = function(group, ensure_unique_name = \"false\")",
97 "\t\t\tgroup <- c(\"group_class\" = \"project\", group)",
98 "\t\t\tself$groups.create(group, ensure_unique_name)",
101 "\t\tprojects.update = function(group, uuid)",
103 "\t\t\tgroup <- c(\"group_class\" = \"project\", group)",
104 "\t\t\tself$groups.update(group, uuid)",
107 "\t\tprojects.list = function(filters = NULL, where = NULL,",
108 "\t\t\torder = NULL, select = NULL, distinct = NULL,",
109 "\t\t\tlimit = \"100\", offset = \"0\", count = \"exact\",",
110 "\t\t\tinclude_trash = NULL)",
112 "\t\t\tfilters[[length(filters) + 1]] <- list(\"group_class\", \"=\", \"project\")",
113 "\t\t\tself$groups.list(filters, where, order, select, distinct,",
114 "\t\t\t limit, offset, count, include_trash)",
117 "\t\tprojects.delete = function(uuid)",
119 "\t\t\tself$groups.delete(uuid)",
124 genClassContent <- function(methodResources, resourceNames)
126 arvadosMethods <- Map(function(resource, resourceName)
128 methodNames <- names(resource$methods)
130 functions <- Map(function(methodMetaData, methodName)
132 #NOTE: Index, show and destroy are aliases for the preferred names
133 # "list", "get" and "delete". Until they are removed from discovery
134 # document we will filter them here.
135 if(methodName %in% c("index", "show", "destroy"))
138 methodName <- paste0(resourceName, ".", methodName)
139 createMethod(methodName, methodMetaData)
141 }, resource$methods, methodNames)
143 unlist(unname(functions))
145 }, methodResources, resourceNames)
150 genAPIClassFooter <- function()
152 c("\t\tgetHostName = function() private$host,",
153 "\t\tgetToken = function() private$token,",
154 "\t\tsetRESTService = function(newREST) private$REST <- newREST,",
155 "\t\tgetRESTService = function() private$REST",
163 "\t\tnumRetries = NULL",
166 "\tcloneable = FALSE",
170 createMethod <- function(name, methodMetaData)
172 args <- getMethodArguments(methodMetaData)
173 signature <- getMethodSignature(name, args)
174 body <- getMethodBody(methodMetaData)
182 getMethodArguments <- function(methodMetaData)
184 request <- methodMetaData$request
187 if(!is.null(request))
189 resourceName <- tolower(request$properties[[1]][[1]])
192 requestArgs <- resourceName
194 requestArgs <- paste(resourceName, "=", "NULL")
197 argNames <- names(methodMetaData$parameters)
199 args <- sapply(argNames, function(argName)
201 arg <- methodMetaData$parameters[[argName]]
205 if(!is.null(arg$default))
206 return(paste0(argName, " = ", "\"", arg$default, "\""))
208 return(paste(argName, "=", "NULL"))
217 getMethodSignature <- function(methodName, args)
219 collapsedArgs <- paste0(args, collapse = ", ")
220 lineLengthLimit <- 40
222 if(nchar(collapsedArgs) > lineLengthLimit)
224 return(paste0("\t\t",
225 formatArgs(paste(methodName, "= function("),
226 "\t", args, ")", lineLengthLimit)))
230 return(paste0("\t\t", methodName, " = function(", collapsedArgs, ")"))
234 getMethodBody <- function(methodMetaData)
236 url <- getRequestURL(methodMetaData)
237 headers <- getRequestHeaders()
238 requestQueryList <- getRequestQueryList(methodMetaData)
239 requestBody <- getRequestBody(methodMetaData)
240 request <- getRequest(methodMetaData)
241 response <- getResponse(methodMetaData)
242 errorCheck <- getErrorCheckingCode()
243 returnStatement <- getReturnObject()
247 requestQueryList, "",
249 request, response, "",
253 paste0("\t\t\t", body)
256 getRequestURL <- function(methodMetaData)
258 endPoint <- methodMetaData$path
259 endPoint <- stringr::str_replace_all(endPoint, "\\{", "${")
260 url <- c(paste0("endPoint <- stringr::str_interp(\"", endPoint, "\")"),
261 paste0("url <- paste0(private$host, endPoint)"))
265 getRequestHeaders <- function()
267 c("headers <- list(Authorization = paste(\"Bearer\", private$token), ",
268 " \"Content-Type\" = \"application/json\")")
271 getRequestQueryList <- function(methodMetaData)
273 queryArgs <- names(Filter(function(arg) arg$location == "query",
274 methodMetaData$parameters))
276 if(length(queryArgs) == 0)
277 return("queryArgs <- NULL")
279 queryArgs <- sapply(queryArgs, function(arg) paste0(arg, " = ", arg))
280 collapsedArgs <- paste0(queryArgs, collapse = ", ")
282 lineLengthLimit <- 40
284 if(nchar(collapsedArgs) > lineLengthLimit)
285 return(formatArgs("queryArgs <- list(", "\t\t\t\t ", queryArgs, ")",
288 return(paste0("queryArgs <- list(", collapsedArgs, ")"))
291 getRequestBody <- function(methodMetaData)
293 request <- methodMetaData$request
295 if(is.null(request) || !request$required)
296 return("body <- NULL")
298 resourceName <- tolower(request$properties[[1]][[1]])
300 requestParameterName <- names(request$properties)[1]
302 c(paste0("if(length(", resourceName, ") > 0)"),
303 paste0("\tbody <- jsonlite::toJSON(list(", resourceName, " = ", resourceName, "), "),
304 "\t auto_unbox = TRUE)",
309 getRequest <- function(methodMetaData)
311 method <- methodMetaData$httpMethod
312 c(paste0("response <- private$REST$http$exec(\"", method, "\", url, headers, body,"),
313 " queryArgs, private$numRetries)")
316 getResponse <- function(methodMetaData)
318 "resource <- private$REST$httpParser$parseJSONResponse(response)"
321 getErrorCheckingCode <- function()
323 c("if(!is.null(resource$errors))",
324 "\tstop(resource$errors)")
327 getReturnObject <- function()
332 #NOTE: Arvados class documentation:
334 genMethodsDoc <- function(methodResources, resourceNames)
336 methodsDoc <- unlist(unname(Map(function(resource, resourceName)
338 methodNames <- names(resource$methods)
340 methodDoc <- Map(function(methodMetaData, methodName)
342 #NOTE: Index, show and destroy are aliases for the preferred names
343 # "list", "get" and "delete". Until they are removed from discovery
344 # document we will filter them here.
345 if(methodName %in% c("index", "show", "destroy"))
348 methodName <- paste0(resourceName, ".", methodName)
349 getMethodDoc(methodName, methodMetaData)
351 }, resource$methods, methodNames)
353 unlist(unname(methodDoc))
355 }, methodResources, resourceNames)))
357 projectDoc <- genProjectMethodsDoc()
359 c(methodsDoc, projectDoc)
362 genAPIClassDoc <- function(methodResources, resourceNames)
366 "#' Arvados class gives users ability to access Arvados REST API.",
368 "#' @section Usage:",
369 "#' \\preformatted{arv = Arvados$new(authToken = NULL, hostName = NULL, numRetries = 0)}",
371 "#' @section Arguments:",
373 "#' \t\\item{authToken}{Authentification token. If not specified ARVADOS_API_TOKEN environment variable will be used.}",
374 "#' \t\\item{hostName}{Host name. If not specified ARVADOS_API_HOST environment variable will be used.}",
375 "#' \t\\item{numRetries}{Number which specifies how many times to retry failed service requests.}",
378 "#' @section Methods:",
380 getAPIClassMethodList(methodResources, resourceNames),
386 "#' arv <- Arvados$new(\"your Arvados token\", \"example.arvadosapi.com\")",
388 "#' collection <- arv$collections.get(\"uuid\")",
390 "#' collectionList <- arv$collections.list(list(list(\"name\", \"like\", \"Test%\")))",
391 "#' collectionList <- listAll(arv$collections.list, list(list(\"name\", \"like\", \"Test%\")))",
393 "#' deletedCollection <- arv$collections.delete(\"uuid\")",
395 "#' updatedCollection <- arv$collections.update(list(name = \"New name\", description = \"New description\"),",
398 "#' createdCollection <- arv$collections.create(list(name = \"Example\",",
399 "#' description = \"This is a test collection\"))",
406 getAPIClassMethodList <- function(methodResources, resourceNames)
408 methodList <- unlist(unname(Map(function(resource, resourceName)
410 methodNames <- names(resource$methods)
413 methodNames[!(methodNames %in% c("index", "show", "destroy"))])
415 }, methodResources, resourceNames)))
417 hardcodedMethods <- c("projects.create", "projects.get",
418 "projects.list", "projects.update", "projects.delete")
419 paste0("#' \t\\item{}{\\code{\\link{", sort(c(methodList, hardcodedMethods)), "}}}")
422 getMethodDoc <- function(methodName, methodMetaData)
424 name <- paste("#' @name", methodName)
425 usage <- getMethodUsage(methodName, methodMetaData)
426 description <- paste("#'", methodName, "is a method defined in Arvados class.")
427 params <- getMethodDescription(methodMetaData)
428 returnValue <- paste("#' @return", methodMetaData$response[["$ref"]], "object.")
430 c(paste("#'", methodName),
442 getMethodUsage <- function(methodName, methodMetaData)
444 lineLengthLimit <- 40
445 args <- getMethodArguments(methodMetaData)
446 c(formatArgs(paste0("#' @usage arv$", methodName,
447 "("), "#' \t", args, ")", lineLengthLimit))
450 getMethodDescription <- function(methodMetaData)
452 request <- methodMetaData$request
455 if(!is.null(request))
457 requestDoc <- unname(unlist(sapply(request$properties, function(prop)
459 className <- sapply(prop, function(ref) ref)
460 objectName <- paste0(tolower(substr(className, 1, 1)),
461 substr(className, 2, nchar(className)))
462 paste("#' @param", objectName, className, "object.")
466 argNames <- names(methodMetaData$parameters)
468 argsDoc <- unname(unlist(sapply(argNames, function(argName)
470 arg <- methodMetaData$parameters[[argName]]
471 argDescription <- arg$description
472 paste("#' @param", argName, argDescription)
475 c(requestDoc, argsDoc)
478 genProjectMethodsDoc <- function()
480 #TODO: Manually update this documentation to reflect changes in discovery document.
483 "#' projects.get is equivalent to groups.get method.",
485 "#' @usage arv$projects.get(uuid)",
486 "#' @param uuid The UUID of the Group in question.",
487 "#' @return Group object.",
488 "#' @name projects.get",
493 "#' projects.create wrapps groups.create method by setting group_class attribute to \"project\".",
495 "#' @usage arv$projects.create(group, ensure_unique_name = \"false\")",
496 "#' @param group Group object.",
497 "#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.",
498 "#' @return Group object.",
499 "#' @name projects.create",
504 "#' projects.update wrapps groups.update method by setting group_class attribute to \"project\".",
506 "#' @usage arv$projects.update(group, uuid)",
507 "#' @param group Group object.",
508 "#' @param uuid The UUID of the Group in question.",
509 "#' @return Group object.",
510 "#' @name projects.update",
515 "#' projects.delete is equivalent to groups.delete method.",
517 "#' @usage arv$project.delete(uuid)",
518 "#' @param uuid The UUID of the Group in question.",
519 "#' @return Group object.",
520 "#' @name projects.delete",
525 "#' projects.list wrapps groups.list method by setting group_class attribute to \"project\".",
527 "#' @usage arv$projects.list(filters = NULL,",
528 "#' where = NULL, order = NULL, distinct = NULL,",
529 "#' limit = \"100\", offset = \"0\", count = \"exact\",",
530 "#' include_trash = NULL, uuid = NULL, recursive = NULL)",
531 "#' @param filters ",
534 "#' @param distinct ",
538 "#' @param include_trash Include items whose is_trashed attribute is true.",
540 "#' @param recursive Include contents from child groups recursively.",
541 "#' @return Group object.",
542 "#' @name projects.list",
547 #NOTE: Utility functions:
549 # This function is used to split very long lines of code into smaller chunks.
550 # This is usually the case when we pass a lot of named argumets to a function.
551 formatArgs <- function(prependAtStart, prependToEachSplit,
552 args, appendAtEnd, lineLength)
556 args[1:(length(args) - 1)] <- paste0(args[1:(length(args) - 1)], ",")
559 args[1] <- paste0(prependAtStart, args[1])
560 args[length(args)] <- paste0(args[length(args)], appendAtEnd)
562 argsLength <- length(args)
566 while(index <= argsLength)
571 while(nchar(line) < lineLength && index <= argsLength)
573 line <- paste(line, args[index])
577 argLines <- c(argLines, line)
580 argLines <- unlist(argLines)
581 argLinesLen <- length(argLines)
584 argLines[2:argLinesLen] <- paste0(prependToEachSplit, argLines[2:argLinesLen])