-
Notifications
You must be signed in to change notification settings - Fork 1
/
sp_dir.R
319 lines (287 loc) · 8.55 KB
/
sp_dir.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#' List SharePoint files and folders
#'
#' @description
#'
#' [sp_dir_info()] is a wrapper for the `list_files` method with some additional
#' features based on [fs::dir_info()]. [sp_dir_ls()] returns a character vector
#' and does not yet include support for the `recurse` argument. If
#' `{fs}` is installed, the size column is formatted using [fs::as_fs_bytes()]
#' and an additional "type" factor column is added with values for directory and
#' file.
#'
#' @param path Path to directory or folder. SharePoint folder URLs are allowed.
#' If `NULL`, path is set to default "/".
#' @param info The information to return: "partial", "name" or "all". If
#' "partial", a data frame is returned containing the name, size, ID and
#' whether the item is a file or folder. If "all", a data frame is returned
#' containing all the properties for each item (this can be large).
#' @param full_names If `TRUE` (default), return the full file path as the name
#' for each item.
#' @param pagesize Maximum number of items to return. Defaults to 1000. Decrease
#' if you are experiencing timeouts.
#' @param recurse If `TRUE`, get info for each directory at the supplied path
#' and combine this info with the item info for the supplied path.
#' @param type Type of item to return. Can be "any", "file", or "directory".
#' "directory" is not a supported option for [sp_dir_ls()]
#' @param regexp Regular expression passed to `grep()` and used to filter the
#' paths before they are returned.
#' @inheritDotParams get_sp_drive -drive_name -drive_id -properties
#' @inheritParams base::grep
#' @inheritParams get_sp_drive
#' @inheritParams get_sp_item
#' @examples
#' dir_url <- "<link to SharePoint directory or drive>"
#'
#' if (is_sp_url(dir_url)) {
#' sp_dir_info(
#' path = dir_url
#' )
#'
#' sp_dir_ls(
#' path = dir_url
#' )
#' }
#'
#' @export
#' @importFrom vctrs vec_slice vec_rbind
sp_dir_info <- function(path = NULL,
...,
info = "partial",
full_names = TRUE,
pagesize = 1000,
drive_name = NULL,
drive_id = NULL,
drive = NULL,
recurse = FALSE,
type = "any",
regexp = NULL,
invert = FALSE,
perl = FALSE,
call = caller_env()) {
if (!is.null(path) && is_sp_url(path)) {
sp_url_parts <- sp_url_parse(path, call = call)
drive_name <- path
path <- str_remove_slash(sp_url_parts[["file_path"]], before = TRUE)
}
drive <- drive %||% get_sp_drive(
drive_name = drive_name,
drive_id = drive_id,
...,
properties = FALSE,
call = call
)
check_ms_drive(drive, call = call)
path <- path %||% "/"
info <- arg_match(info, values = c("partial", "name", "all"), call = call)
type <- arg_match(type, c("any", "file", "directory"), error_call = call)
return_type <- NULL
if (recurse && (type == "file")) {
cli::cli_alert_warning(
"{.arg type} is always set to {.val {any}} if {.code recurse = TRUE}"
)
type <- "any"
}
if (type == "file") {
item_list <- drive$list_files(
path = path,
info = info,
full_names = full_names,
pagesize = pagesize
)
} else {
item_list <- drive$list_items(
path = path,
info = info,
full_names = full_names,
pagesize = pagesize
)
}
if (!is.null(regexp)) {
path_name <- item_list
if (is.data.frame(item_list)) {
path_name <- item_list[["name"]]
}
item_list <- vctrs::vec_slice(
item_list,
i = grep(regexp, path_name, perl = perl, invert = invert),
error_call = call
)
}
if (!is.data.frame(item_list)) {
return(item_list)
}
item_list <- switch(type,
any = item_list,
file = item_list[!item_list[["isdir"]], ],
directory = item_list[item_list[["isdir"]], ]
)
if (is_installed("fs")) {
item_list[["size"]] <- vec_fmt_sp_item_size(item_list[["size"]])
item_list[["type"]] <- factor(
vapply(
item_list[["isdir"]],
function(x) {
if (x) {
return("directory")
}
"file"
},
NA_character_
),
levels = c("directory", "file")
)
}
if (!recurse || (type == "file") || !any(item_list[["isdir"]])) {
return(item_list)
}
dir_list <- item_list[item_list[["isdir"]], ]
dir_name <- dir_list[["name"]]
if (full_names) {
dir_name <- str_remove_slash(dir_name, before = TRUE)
}
dir_item_list <- map(
cli::cli_progress_along(dir_name),
function(i) {
sp_dir_info(
dir_name[[i]],
drive = drive,
info = info,
full_names = full_names,
pagesize = pagesize,
recurse = recurse,
type = type,
regexp = regexp,
call = call
)
}
)
dir_item_list <- c(list(item_list), dir_item_list)
vctrs::vec_rbind(!!!dir_item_list, .error_call = call)
}
#' @noRd
vec_fmt_sp_item_size <- function(x) {
fs::as_fs_bytes(as.double(x))
}
#' @noRd
fmt_sp_item_size <- function(data, size_col = "size") {
data[[size_col]] <- vec_fmt_sp_item_size(data[[size_col]])
data
}
#' @rdname sp_dir_info
#' @name sp_dir_ls
#' @export
sp_dir_ls <- function(path = NULL,
...,
full_names = FALSE,
pagesize = 1000,
drive_name = NULL,
drive_id = NULL,
drive = NULL,
type = "any",
regexp = NULL,
invert = FALSE,
perl = FALSE,
call = caller_env()) {
sp_dir_info(
path = path,
...,
info = "name",
full_names = full_names,
pagesize = pagesize,
drive_name = drive_name,
drive_id = drive_id,
drive = drive,
type = type,
regexp = regexp,
invert = invert,
perl = perl,
call = call
)
}
#' Create SharePoint folders
#'
#' [sp_dir_create()] is a wrapper for the `create_folder` method that handles
#' character vectors. If `drive_name` is a folder URL and `relative` is `TRUE`,
#' the values for `path` are appended to the file path parsed from the url.
#'
#' @param path A character vector of one or more paths.
#' @inheritParams get_sp_drive
#' @inheritParams get_sp_item
#' @param relative If `TRUE` and `drive_name` is a folder URL, the values for
#' `path` are appended to the file path parsed from the url. If `relative` is
#' a character vector, it must be length 1 or the same length as path and
#' appended to path as a vector of parent directories. The second option takes
#' precedence over any file path parsed from the url.
#' @inheritDotParams get_sp_drive -drive_name -drive_id -properties
#' @examples
#' drive_url <- "<link to SharePoint drive>"
#'
#' if (is_sp_url(drive_url)) {
#' sp_dir_create(
#' path = "parent_folder/subfolder",
#' drive_name = drive_url
#' )
#'
#' sp_dir_create(
#' path = c("subfolder1", "subfolder2", "subfolder3"),
#' relative = "parent_folder",
#' drive_name = drive_url
#' )
#' }
#'
#' dir_url <- "<link to SharePoint directory>"
#'
#' if (is_sp_url(dir_url)) {
#' sp_dir_create(
#' path = c("subfolder1", "subfolder2", "subfolder3"),
#' drive_name = dir_url,
#' relative = TRUE
#' )
#' }
#'
#' @export
#' @importFrom vctrs vec_recycle
#' @importFrom cli cli_progress_along cli_warn cli_progress_done
sp_dir_create <- function(path,
...,
drive_name = NULL,
drive_id = NULL,
drive = NULL,
relative = FALSE,
call = caller_env()) {
drive <- drive %||%
get_sp_drive(
drive_name = drive_name,
drive_id = drive_id,
...,
properties = FALSE,
call = call
)
if (is_true(relative) || is_character(relative)) {
if (!is_character(relative) && is_sp_folder_url(drive_name)) {
relative <- str_remove_slash(sp_url_parse(drive_name)[["file_path"]])
}
relative <- vctrs::vec_recycle(
relative,
size = length(path),
x_arg = "relative",
call = call
)
path <- str_c_url(relative, path)
}
walk(
cli::cli_progress_along(path),
\(i) {
withCallingHandlers(
drive$create_folder(path = path[[i]]),
error = function(cnd) {
cli::cli_warn(
cnd$message
)
}
)
}
)
cli::cli_progress_done()
invisible(path)
}