github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fs/rc/config.go (about)

     1  // Implement config options reading and writing
     2  //
     3  // This is done here rather than in fs/fs.go so we don't cause a circular dependency
     4  
     5  package rc
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  
    11  	"github.com/rclone/rclone/fs"
    12  	"github.com/rclone/rclone/fs/filter"
    13  )
    14  
    15  var (
    16  	optionBlock  = map[string]interface{}{}
    17  	optionReload = map[string]func(context.Context) error{}
    18  )
    19  
    20  // AddOption adds an option set
    21  func AddOption(name string, option interface{}) {
    22  	optionBlock[name] = option
    23  }
    24  
    25  // AddOptionReload adds an option set with a reload function to be
    26  // called when options are changed
    27  func AddOptionReload(name string, option interface{}, reload func(context.Context) error) {
    28  	optionBlock[name] = option
    29  	optionReload[name] = reload
    30  }
    31  
    32  func init() {
    33  	Add(Call{
    34  		Path:  "options/blocks",
    35  		Fn:    rcOptionsBlocks,
    36  		Title: "List all the option blocks",
    37  		Help: `Returns:
    38  - options - a list of the options block names`,
    39  	})
    40  }
    41  
    42  // Show the list of all the option blocks
    43  func rcOptionsBlocks(ctx context.Context, in Params) (out Params, err error) {
    44  	options := []string{}
    45  	for name := range optionBlock {
    46  		options = append(options, name)
    47  	}
    48  	out = make(Params)
    49  	out["options"] = options
    50  	return out, nil
    51  }
    52  
    53  func init() {
    54  	Add(Call{
    55  		Path:  "options/get",
    56  		Fn:    rcOptionsGet,
    57  		Title: "Get all the global options",
    58  		Help: `Returns an object where keys are option block names and values are an
    59  object with the current option values in.
    60  
    61  Note that these are the global options which are unaffected by use of
    62  the _config and _filter parameters. If you wish to read the parameters
    63  set in _config then use options/config and for _filter use options/filter.
    64  
    65  This shows the internal names of the option within rclone which should
    66  map to the external options very easily with a few exceptions.
    67  `,
    68  	})
    69  }
    70  
    71  // Show the list of all the option blocks
    72  func rcOptionsGet(ctx context.Context, in Params) (out Params, err error) {
    73  	out = make(Params)
    74  	for name, options := range optionBlock {
    75  		out[name] = options
    76  	}
    77  	return out, nil
    78  }
    79  
    80  func init() {
    81  	Add(Call{
    82  		Path:  "options/local",
    83  		Fn:    rcOptionsLocal,
    84  		Title: "Get the currently active config for this call",
    85  		Help: `Returns an object with the keys "config" and "filter".
    86  The "config" key contains the local config and the "filter" key contains
    87  the local filters.
    88  
    89  Note that these are the local options specific to this rc call. If
    90  _config was not supplied then they will be the global options.
    91  Likewise with "_filter".
    92  
    93  This call is mostly useful for seeing if _config and _filter passing
    94  is working.
    95  
    96  This shows the internal names of the option within rclone which should
    97  map to the external options very easily with a few exceptions.
    98  `,
    99  	})
   100  }
   101  
   102  // Show the current config
   103  func rcOptionsLocal(ctx context.Context, in Params) (out Params, err error) {
   104  	out = make(Params)
   105  	out["config"] = fs.GetConfig(ctx)
   106  	out["filter"] = filter.GetConfig(ctx).Opt
   107  	return out, nil
   108  }
   109  
   110  func init() {
   111  	Add(Call{
   112  		Path:  "options/set",
   113  		Fn:    rcOptionsSet,
   114  		Title: "Set an option",
   115  		Help: `Parameters:
   116  
   117  - option block name containing an object with
   118    - key: value
   119  
   120  Repeated as often as required.
   121  
   122  Only supply the options you wish to change.  If an option is unknown
   123  it will be silently ignored.  Not all options will have an effect when
   124  changed like this.
   125  
   126  For example:
   127  
   128  This sets DEBUG level logs (-vv) (these can be set by number or string)
   129  
   130      rclone rc options/set --json '{"main": {"LogLevel": "DEBUG"}}'
   131      rclone rc options/set --json '{"main": {"LogLevel": 8}}'
   132  
   133  And this sets INFO level logs (-v)
   134  
   135      rclone rc options/set --json '{"main": {"LogLevel": "INFO"}}'
   136  
   137  And this sets NOTICE level logs (normal without -v)
   138  
   139      rclone rc options/set --json '{"main": {"LogLevel": "NOTICE"}}'
   140  `,
   141  	})
   142  }
   143  
   144  // Set an option in an option block
   145  func rcOptionsSet(ctx context.Context, in Params) (out Params, err error) {
   146  	for name, options := range in {
   147  		current := optionBlock[name]
   148  		if current == nil {
   149  			return nil, fmt.Errorf("unknown option block %q", name)
   150  		}
   151  		err := Reshape(current, options)
   152  		if err != nil {
   153  			return nil, fmt.Errorf("failed to write options from block %q: %w", name, err)
   154  		}
   155  		if reload := optionReload[name]; reload != nil {
   156  			err = reload(ctx)
   157  			if err != nil {
   158  				return nil, fmt.Errorf("failed to reload options from block %q: %w", name, err)
   159  			}
   160  		}
   161  	}
   162  	return out, nil
   163  }