github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/fs/operations/rc.go (about) 1 package operations 2 3 import ( 4 "context" 5 "strings" 6 7 "github.com/pkg/errors" 8 "github.com/rclone/rclone/fs" 9 "github.com/rclone/rclone/fs/rc" 10 ) 11 12 func init() { 13 rc.Add(rc.Call{ 14 Path: "operations/list", 15 AuthRequired: true, 16 Fn: rcList, 17 Title: "List the given remote and path in JSON format", 18 Help: `This takes the following parameters 19 20 - fs - a remote name string eg "drive:" 21 - remote - a path within that remote eg "dir" 22 - opt - a dictionary of options to control the listing (optional) 23 - recurse - If set recurse directories 24 - noModTime - If set return modification time 25 - showEncrypted - If set show decrypted names 26 - showOrigIDs - If set show the IDs for each item if known 27 - showHash - If set return a dictionary of hashes 28 29 The result is 30 31 - list 32 - This is an array of objects as described in the lsjson command 33 34 See the [lsjson command](/commands/rclone_lsjson/) for more information on the above and examples. 35 `, 36 }) 37 } 38 39 // List the directory 40 func rcList(ctx context.Context, in rc.Params) (out rc.Params, err error) { 41 f, remote, err := rc.GetFsAndRemote(in) 42 if err != nil { 43 return nil, err 44 } 45 var opt ListJSONOpt 46 err = in.GetStruct("opt", &opt) 47 if rc.NotErrParamNotFound(err) { 48 return nil, err 49 } 50 var list = []*ListJSONItem{} 51 err = ListJSON(ctx, f, remote, &opt, func(item *ListJSONItem) error { 52 list = append(list, item) 53 return nil 54 }) 55 if err != nil { 56 return nil, err 57 } 58 out = make(rc.Params) 59 out["list"] = list 60 return out, nil 61 } 62 63 func init() { 64 rc.Add(rc.Call{ 65 Path: "operations/about", 66 AuthRequired: true, 67 Fn: rcAbout, 68 Title: "Return the space used on the remote", 69 Help: `This takes the following parameters 70 71 - fs - a remote name string eg "drive:" 72 73 The result is as returned from rclone about --json 74 75 See the [about command](/commands/rclone_size/) command for more information on the above. 76 `, 77 }) 78 } 79 80 // About the remote 81 func rcAbout(ctx context.Context, in rc.Params) (out rc.Params, err error) { 82 f, err := rc.GetFs(in) 83 if err != nil { 84 return nil, err 85 } 86 doAbout := f.Features().About 87 if doAbout == nil { 88 return nil, errors.Errorf("%v doesn't support about", f) 89 } 90 u, err := doAbout(ctx) 91 if err != nil { 92 return nil, errors.Wrap(err, "about call failed") 93 } 94 err = rc.Reshape(&out, u) 95 if err != nil { 96 return nil, errors.Wrap(err, "about Reshape failed") 97 } 98 return out, nil 99 } 100 101 func init() { 102 for _, copy := range []bool{false, true} { 103 copy := copy 104 name := "Move" 105 if copy { 106 name = "Copy" 107 } 108 rc.Add(rc.Call{ 109 Path: "operations/" + strings.ToLower(name) + "file", 110 AuthRequired: true, 111 Fn: func(ctx context.Context, in rc.Params) (rc.Params, error) { 112 return rcMoveOrCopyFile(ctx, in, copy) 113 }, 114 Title: name + " a file from source remote to destination remote", 115 Help: `This takes the following parameters 116 117 - srcFs - a remote name string eg "drive:" for the source 118 - srcRemote - a path within that remote eg "file.txt" for the source 119 - dstFs - a remote name string eg "drive2:" for the destination 120 - dstRemote - a path within that remote eg "file2.txt" for the destination 121 `, 122 }) 123 } 124 } 125 126 // Copy a file 127 func rcMoveOrCopyFile(ctx context.Context, in rc.Params, cp bool) (out rc.Params, err error) { 128 srcFs, srcRemote, err := rc.GetFsAndRemoteNamed(in, "srcFs", "srcRemote") 129 if err != nil { 130 return nil, err 131 } 132 dstFs, dstRemote, err := rc.GetFsAndRemoteNamed(in, "dstFs", "dstRemote") 133 if err != nil { 134 return nil, err 135 } 136 return nil, moveOrCopyFile(ctx, dstFs, srcFs, dstRemote, srcRemote, cp) 137 } 138 139 func init() { 140 for _, op := range []struct { 141 name string 142 title string 143 help string 144 noRemote bool 145 }{ 146 {name: "mkdir", title: "Make a destination directory or container"}, 147 {name: "rmdir", title: "Remove an empty directory or container"}, 148 {name: "purge", title: "Remove a directory or container and all of its contents"}, 149 {name: "rmdirs", title: "Remove all the empty directories in the path", help: "- leaveRoot - boolean, set to true not to delete the root\n"}, 150 {name: "delete", title: "Remove files in the path", noRemote: true}, 151 {name: "deletefile", title: "Remove the single file pointed to"}, 152 {name: "copyurl", title: "Copy the URL to the object", help: "- url - string, URL to read from\n - autoFilename - boolean, set to true to retrieve destination file name from url"}, 153 {name: "cleanup", title: "Remove trashed files in the remote or path", noRemote: true}, 154 } { 155 op := op 156 remote := "- remote - a path within that remote eg \"dir\"\n" 157 if op.noRemote { 158 remote = "" 159 } 160 rc.Add(rc.Call{ 161 Path: "operations/" + op.name, 162 AuthRequired: true, 163 Fn: func(ctx context.Context, in rc.Params) (rc.Params, error) { 164 return rcSingleCommand(ctx, in, op.name, op.noRemote) 165 }, 166 Title: op.title, 167 Help: `This takes the following parameters 168 169 - fs - a remote name string eg "drive:" 170 ` + remote + op.help + ` 171 See the [` + op.name + ` command](/commands/rclone_` + op.name + `/) command for more information on the above. 172 `, 173 }) 174 } 175 } 176 177 // Run a single command, eg Mkdir 178 func rcSingleCommand(ctx context.Context, in rc.Params, name string, noRemote bool) (out rc.Params, err error) { 179 var ( 180 f fs.Fs 181 remote string 182 ) 183 if noRemote { 184 f, err = rc.GetFs(in) 185 } else { 186 f, remote, err = rc.GetFsAndRemote(in) 187 } 188 if err != nil { 189 return nil, err 190 } 191 switch name { 192 case "mkdir": 193 return nil, Mkdir(ctx, f, remote) 194 case "rmdir": 195 return nil, Rmdir(ctx, f, remote) 196 case "purge": 197 return nil, Purge(ctx, f, remote) 198 case "rmdirs": 199 leaveRoot, err := in.GetBool("leaveRoot") 200 if rc.NotErrParamNotFound(err) { 201 return nil, err 202 } 203 return nil, Rmdirs(ctx, f, remote, leaveRoot) 204 case "delete": 205 return nil, Delete(ctx, f) 206 case "deletefile": 207 o, err := f.NewObject(ctx, remote) 208 if err != nil { 209 return nil, err 210 } 211 return nil, DeleteFile(ctx, o) 212 case "copyurl": 213 url, err := in.GetString("url") 214 if err != nil { 215 return nil, err 216 } 217 autoFilename, _ := in.GetBool("autoFilename") 218 noClobber, _ := in.GetBool("noClobber") 219 220 _, err = CopyURL(ctx, f, remote, url, autoFilename, noClobber) 221 return nil, err 222 case "cleanup": 223 return nil, CleanUp(ctx, f) 224 } 225 panic("unknown rcSingleCommand type") 226 } 227 228 func init() { 229 rc.Add(rc.Call{ 230 Path: "operations/size", 231 AuthRequired: true, 232 Fn: rcSize, 233 Title: "Count the number of bytes and files in remote", 234 Help: `This takes the following parameters 235 236 - fs - a remote name string eg "drive:path/to/dir" 237 238 Returns 239 240 - count - number of files 241 - bytes - number of bytes in those files 242 243 See the [size command](/commands/rclone_size/) command for more information on the above. 244 `, 245 }) 246 } 247 248 // Size a directory 249 func rcSize(ctx context.Context, in rc.Params) (out rc.Params, err error) { 250 f, err := rc.GetFs(in) 251 if err != nil { 252 return nil, err 253 } 254 count, bytes, err := Count(ctx, f) 255 if err != nil { 256 return nil, err 257 } 258 out = make(rc.Params) 259 out["count"] = count 260 out["bytes"] = bytes 261 return out, nil 262 } 263 264 func init() { 265 rc.Add(rc.Call{ 266 Path: "operations/publiclink", 267 AuthRequired: true, 268 Fn: rcPublicLink, 269 Title: "Create or retrieve a public link to the given file or folder.", 270 Help: `This takes the following parameters 271 272 - fs - a remote name string eg "drive:" 273 - remote - a path within that remote eg "dir" 274 275 Returns 276 277 - url - URL of the resource 278 279 See the [link command](/commands/rclone_link/) command for more information on the above. 280 `, 281 }) 282 } 283 284 // Make a public link 285 func rcPublicLink(ctx context.Context, in rc.Params) (out rc.Params, err error) { 286 f, remote, err := rc.GetFsAndRemote(in) 287 if err != nil { 288 return nil, err 289 } 290 url, err := PublicLink(ctx, f, remote) 291 if err != nil { 292 return nil, err 293 } 294 out = make(rc.Params) 295 out["url"] = url 296 return out, nil 297 } 298 299 func init() { 300 rc.Add(rc.Call{ 301 Path: "operations/fsinfo", 302 Fn: rcFsInfo, 303 Title: "Return information about the remote", 304 Help: `This takes the following parameters 305 306 - fs - a remote name string eg "drive:" 307 308 This returns info about the remote passed in; 309 310 ` + "```" + ` 311 { 312 // optional features and whether they are available or not 313 "Features": { 314 "About": true, 315 "BucketBased": false, 316 "CanHaveEmptyDirectories": true, 317 "CaseInsensitive": false, 318 "ChangeNotify": false, 319 "CleanUp": false, 320 "Copy": false, 321 "DirCacheFlush": false, 322 "DirMove": true, 323 "DuplicateFiles": false, 324 "GetTier": false, 325 "ListR": false, 326 "MergeDirs": false, 327 "Move": true, 328 "OpenWriterAt": true, 329 "PublicLink": false, 330 "Purge": true, 331 "PutStream": true, 332 "PutUnchecked": false, 333 "ReadMimeType": false, 334 "ServerSideAcrossConfigs": false, 335 "SetTier": false, 336 "SetWrapper": false, 337 "UnWrap": false, 338 "WrapFs": false, 339 "WriteMimeType": false 340 }, 341 // Names of hashes available 342 "Hashes": [ 343 "MD5", 344 "SHA-1", 345 "DropboxHash", 346 "QuickXorHash" 347 ], 348 "Name": "local", // Name as created 349 "Precision": 1, // Precision of timestamps in ns 350 "Root": "/", // Path as created 351 "String": "Local file system at /" // how the remote will appear in logs 352 } 353 ` + "```" + ` 354 355 This command does not have a command line equivalent so use this instead: 356 357 rclone rc --loopback operations/fsinfo fs=remote: 358 359 `, 360 }) 361 } 362 363 // Fsinfo the remote 364 func rcFsInfo(ctx context.Context, in rc.Params) (out rc.Params, err error) { 365 f, err := rc.GetFs(in) 366 if err != nil { 367 return nil, err 368 } 369 info := GetFsInfo(f) 370 err = rc.Reshape(&out, info) 371 if err != nil { 372 return nil, errors.Wrap(err, "fsinfo Reshape failed") 373 } 374 return out, nil 375 } 376 377 func init() { 378 rc.Add(rc.Call{ 379 Path: "backend/command", 380 AuthRequired: true, 381 Fn: rcBackend, 382 Title: "Runs a backend command.", 383 Help: `This takes the following parameters 384 385 - command - a string with the command name 386 - fs - a remote name string eg "drive:" 387 - arg - a list of arguments for the backend command 388 - opt - a map of string to string of options 389 390 Returns 391 392 - result - result from the backend command 393 394 For example 395 396 rclone rc backend/command command=noop fs=. -o echo=yes -o blue -a path1 -a path2 397 398 Returns 399 400 ` + "```" + ` 401 { 402 "result": { 403 "arg": [ 404 "path1", 405 "path2" 406 ], 407 "name": "noop", 408 "opt": { 409 "blue": "", 410 "echo": "yes" 411 } 412 } 413 } 414 ` + "```" + ` 415 416 Note that this is the direct equivalent of using this "backend" 417 command: 418 419 rclone backend noop . -o echo=yes -o blue path1 path2 420 421 Note that arguments must be preceded by the "-a" flag 422 423 See the [backend](/commands/rclone_backend/) command for more information. 424 `, 425 }) 426 } 427 428 // Make a public link 429 func rcBackend(ctx context.Context, in rc.Params) (out rc.Params, err error) { 430 f, err := rc.GetFs(in) 431 if err != nil { 432 return nil, err 433 } 434 doCommand := f.Features().Command 435 if doCommand == nil { 436 return nil, errors.Errorf("%v: doesn't support backend commands", f) 437 } 438 command, err := in.GetString("command") 439 if err != nil { 440 return nil, err 441 } 442 var opt = map[string]string{} 443 err = in.GetStructMissingOK("opt", &opt) 444 if err != nil { 445 return nil, err 446 } 447 var arg = []string{} 448 err = in.GetStructMissingOK("arg", &arg) 449 if err != nil { 450 return nil, err 451 } 452 result, err := doCommand(context.Background(), command, arg, opt) 453 if err != nil { 454 return nil, errors.Wrapf(err, "command %q failed", command) 455 456 } 457 out = make(rc.Params) 458 out["result"] = result 459 return out, nil 460 }