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  }