Improve Collections create and move methods and update documentation
[arvados.git] / sdk / R / R / ArvadosFile.R
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: Apache-2.0
4
5 source("./R/util.R")
6
7 #' ArvadosFile
8 #'
9 #' ArvadosFile class represents a file inside Arvados collection.
10 #'
11 #' @section Usage:
12 #' \preformatted{file = ArvadosFile$new(name)}
13 #'
14 #' @section Arguments:
15 #' \describe{
16 #'   \item{name}{Name of the file.}
17 #' }
18 #'
19 #' @section Methods:
20 #' \describe{
21 #'   \item{getName()}{Returns name of the file.}
22 #'   \item{getRelativePath()}{Returns file path relative to the root.}
23 #'   \item{read(contentType = "raw", offset = 0, length = 0)}{Read file content.}
24 #'   \item{write(content, contentType = "text/html")}{Write to file (override current content of the file).}
25 #'   \item{connection(rw)}{Get connection opened in "read" or "write" mode.}
26 #'   \item{flush()}{Write connections content to a file (override current content of the file).}
27 #'   \item{remove(name)}{Removes ArvadosFile or Subcollection specified by name from the subcollection.}
28 #'   \item{getSizeInBytes()}{Returns file size in bytes.}
29 #'   \item{move(destination)}{Moves file to a new location inside collection.}
30 #'   \item{copy(destination)}{Copies file to a new location inside collection.}
31 #' }
32 #'
33 #' @name ArvadosFile
34 #' @examples
35 #' \dontrun{
36 #' myFile <- ArvadosFile$new("myFile")
37 #'
38 #' myFile$write("This is new file content")
39 #' fileContent <- myFile$read()
40 #' fileContent <- myFile$read("text")
41 #' fileContent <- myFile$read("raw", offset = 8, length = 4)
42 #'
43 #' #Write a table:
44 #' arvConnection <- myFile$connection("w")
45 #' write.table(mytable, arvConnection)
46 #' arvadosFile$flush()
47 #'
48 #' #Read a table:
49 #' arvConnection <- myFile$connection("r")
50 #' mytable <- read.table(arvConnection)
51 #'
52 #' myFile$move("newFolder/myFile")
53 #' myFile$copy("newFolder/myFile")
54 #' }
55 NULL
56
57 #' @export
58 ArvadosFile <- R6::R6Class(
59
60     "ArvadosFile",
61
62     public = list(
63
64         initialize = function(name)
65         {
66             if(name == "")
67                 stop("Invalid name.")
68
69             private$name <- name
70         },
71
72         getName = function() private$name,
73
74         getFileListing = function(fullpath = TRUE)
75         {
76             self$getName()
77         },
78
79         getSizeInBytes = function()
80         {
81             if(is.null(private$collection))
82                 return(0)
83
84             REST <- private$collection$getRESTService()
85
86             fileSize <- REST$getResourceSize(self$getRelativePath(),
87                                              private$collection$uuid)
88             fileSize
89         },
90
91         get = function(fileLikeObjectName)
92         {
93             return(NULL)
94         },
95
96         getFirst = function()
97         {
98             return(NULL)
99         },
100
101         getCollection = function() private$collection,
102
103         setCollection = function(collection, setRecursively = TRUE)
104         {
105             private$collection <- collection
106         },
107
108         getRelativePath = function()
109         {
110             relativePath <- c(private$name)
111             parent <- private$parent
112
113             while(!is.null(parent))
114             {
115                 relativePath <- c(parent$getName(), relativePath)
116                 parent <- parent$getParent()
117             }
118
119             relativePath <- relativePath[relativePath != ""]
120             paste0(relativePath, collapse = "/")
121         },
122
123         getParent = function() private$parent,
124
125         setParent = function(newParent) private$parent <- newParent,
126
127         read = function(contentType = "raw", offset = 0, length = 0)
128         {
129             if(is.null(private$collection))
130                 stop("ArvadosFile doesn't belong to any collection.")
131
132             if(offset < 0 || length < 0)
133                 stop("Offset and length must be positive values.")
134
135             REST <- private$collection$getRESTService()
136
137             fileContent <- REST$read(self$getRelativePath(),
138                                      private$collection$uuid,
139                                      contentType, offset, length)
140             fileContent
141         },
142
143         connection = function(rw)
144         {
145             if (rw == "r" || rw == "rb")
146             {
147                 REST <- private$collection$getRESTService()
148                 return(REST$getConnection(self$getRelativePath(),
149                                           private$collection$uuid,
150                                           rw))
151             }
152             else if (rw == "w")
153             {
154                 private$buffer <- textConnection(NULL, "w")
155
156                 return(private$buffer)
157             }
158         },
159
160         flush = function()
161         {
162             v <- textConnectionValue(private$buffer)
163             close(private$buffer)
164             self$write(paste(v, collapse='\n'))
165         },
166
167         write = function(content, contentType = "text/html")
168         {
169             if(is.null(private$collection))
170                 stop("ArvadosFile doesn't belong to any collection.")
171
172             REST <- private$collection$getRESTService()
173
174             writeResult <- REST$write(self$getRelativePath(),
175                                       private$collection$uuid,
176                                       content, contentType)
177             writeResult
178         },
179
180         move = function(destination)
181         {
182             if(is.null(private$collection))
183                 stop("ArvadosFile doesn't belong to any collection.")
184
185             destination <- trimFromEnd(destination, "/")
186             nameAndPath <- splitToPathAndName(destination)
187
188             newParent <- private$collection$get(nameAndPath$path)
189
190             if(is.null(newParent))
191                 stop("Unable to get destination subcollection.")
192
193             childWithSameName <- newParent$get(nameAndPath$name)
194
195             if(!is.null(childWithSameName))
196                 stop("Destination already contains content with same name.")
197
198             REST <- private$collection$getRESTService()
199             REST$move(self$getRelativePath(),
200                       paste0(newParent$getRelativePath(), "/", nameAndPath$name),
201                       private$collection$uuid)
202
203             private$dettachFromCurrentParent()
204             private$attachToNewParent(self, newParent)
205
206             private$parent <- newParent
207             private$name <- nameAndPath$name
208
209             self
210         },
211
212         copy = function(destination)
213         {
214             if(is.null(private$collection))
215                 stop("ArvadosFile doesn't belong to any collection.")
216
217             destination <- trimFromEnd(destination, "/")
218             nameAndPath <- splitToPathAndName(destination)
219
220             newParent <- private$collection$get(nameAndPath$path)
221
222             if(is.null(newParent))
223                 stop("Unable to get destination subcollection.")
224
225             childWithSameName <- newParent$get(nameAndPath$name)
226
227             if(!is.null(childWithSameName))
228                 stop("Destination already contains content with same name.")
229
230             REST <- private$collection$getRESTService()
231             REST$copy(self$getRelativePath(),
232                       paste0(newParent$getRelativePath(), "/", nameAndPath$name),
233                       private$collection$uuid)
234
235             newFile <- self$duplicate(nameAndPath$name)
236             newFile$setCollection(self$getCollection())
237             private$attachToNewParent(newFile, newParent)
238             newFile$setParent(newParent)
239
240             newFile
241         },
242
243         duplicate = function(newName = NULL)
244         {
245             name <- if(!is.null(newName)) newName else private$name
246             newFile <- ArvadosFile$new(name)
247             newFile
248         }
249     ),
250
251     private = list(
252
253         name       = NULL,
254         size       = NULL,
255         parent     = NULL,
256         collection = NULL,
257         buffer     = NULL,
258
259         attachToNewParent = function(content, newParent)
260         {
261             # We temporary set parents collection to NULL. This will ensure that
262             # add method doesn't post this file on REST.
263             # We also need to set content's collection to NULL because
264             # add method throws exception if we try to add content that already
265             # belongs to a collection.
266             parentsCollection <- newParent$getCollection()
267             content$setCollection(NULL, setRecursively = FALSE)
268             newParent$setCollection(NULL, setRecursively = FALSE)
269             newParent$add(content)
270             content$setCollection(parentsCollection, setRecursively = FALSE)
271             newParent$setCollection(parentsCollection, setRecursively = FALSE)
272         },
273
274         dettachFromCurrentParent = function()
275         {
276             # We temporary set parents collection to NULL. This will ensure that
277             # remove method doesn't remove this file from REST.
278             parent <- private$parent
279             parentsCollection <- parent$getCollection()
280             parent$setCollection(NULL, setRecursively = FALSE)
281             parent$remove(private$name)
282             parent$setCollection(parentsCollection, setRecursively = FALSE)
283         }
284     ),
285
286     cloneable = FALSE
287 )
288
289 #' print.ArvadosFile
290 #'
291 #' Custom print function for ArvadosFile class
292 #'
293 #' @param x Instance of ArvadosFile class
294 #' @param ... Optional arguments.
295 #' @export
296 print.ArvadosFile = function(x, ...)
297 {
298     collection   <- NULL
299     relativePath <- x$getRelativePath()
300
301     if(!is.null(x$getCollection()))
302     {
303         collection <- x$getCollection()$uuid
304         relativePath <- paste0("/", relativePath)
305     }
306
307     cat(paste0("Type:          ", "\"", "ArvadosFile", "\""), sep = "\n")
308     cat(paste0("Name:          ", "\"", x$getName(),   "\""), sep = "\n")
309     cat(paste0("Relative path: ", "\"", relativePath,  "\""), sep = "\n")
310     cat(paste0("Collection:    ", "\"", collection,    "\""), sep = "\n")
311 }