lib: add plugin support
This enables loading plugins from RCLONE_PLUGIN_PATH if set.
This commit is contained in:
parent
349112df6b
commit
44b603d2bd
4 changed files with 93 additions and 1 deletions
|
@ -376,3 +376,37 @@ Add your fs to the docs - you'll need to pick an icon for it from [fontawesome](
|
|||
* `docs/content/about.md` - front page of rclone.org
|
||||
* `docs/layouts/chrome/navbar.html` - add it to the website navigation
|
||||
* `bin/make_manual.py` - add the page to the `docs` constant
|
||||
|
||||
## Writing a plugin ##
|
||||
|
||||
New features (backends, commands) can also be added "out-of-tree", through Go plugins.
|
||||
Changes will be kept in a dynamically loaded file instead of being compiled into the main binary.
|
||||
This is useful if you can't merge your changes upstream or don't want to maintain a fork of rclone.
|
||||
|
||||
Usage
|
||||
|
||||
- Naming
|
||||
- Plugins names must have the pattern `librcloneplugin_KIND_NAME.so`.
|
||||
- `KIND` should be one of `backend`, `command` or `bundle`.
|
||||
- Example: A plugin with backend support for PiFS would be called
|
||||
`librcloneplugin_backend_pifs.so`.
|
||||
- Loading
|
||||
- Supported on macOS & Linux as of now. ([Go issue for Windows support](https://github.com/golang/go/issues/19282))
|
||||
- Supported on rclone v1.50 or greater.
|
||||
- All plugins in the folder specified by variable `$RCLONE_PLUGIN_PATH` are loaded.
|
||||
- If this variable doesn't exist, plugin support is disabled.
|
||||
- Plugins must be compiled against the exact version of rclone to work.
|
||||
(The rclone used during building the plugin must be the same as the source of rclone)
|
||||
|
||||
Building
|
||||
|
||||
To turn your existing additions into a Go plugin, move them to an external repository
|
||||
and change the top-level package name to `main`.
|
||||
|
||||
Check `rclone --version` and make sure that the plugin's rclone dependency and host Go version match.
|
||||
|
||||
Then, run `go build -buildmode=plugin -o PLUGIN_NAME.so .` to build the plugin.
|
||||
|
||||
[Go reference](https://godoc.org/github.com/rclone/rclone/lib/plugin)
|
||||
|
||||
[Minimal example](https://gist.github.com/terorie/21b517ee347828e899e1913efc1d684f)
|
||||
|
|
16
lib/plugin/package.go
Normal file
16
lib/plugin/package.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Package plugin implements loading out-of-tree storage backends
|
||||
// using https://golang.org/pkg/plugin/ on Linux and macOS.
|
||||
//
|
||||
// If the $RCLONE_PLUGIN_PATH is present, any Go plugins in that dir
|
||||
// named like librcloneplugin_NAME.so will be loaded.
|
||||
//
|
||||
// To create a plugin, write the backend package like it was in-tree
|
||||
// but set the package name to "main". Then, build the plugin with
|
||||
//
|
||||
// go build -buildmode=plugin -o librcloneplugin_NAME.so
|
||||
//
|
||||
// where NAME equals the plugin's fs.RegInfo.Name.
|
||||
package plugin
|
||||
|
||||
// Build for plugin for unsupported platforms to stop go complaining
|
||||
// about "no buildable Go source files".
|
41
lib/plugin/plugin.go
Normal file
41
lib/plugin/plugin.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
// +build darwin linux
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"plugin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dir := os.Getenv("RCLONE_PLUGIN_PATH")
|
||||
if dir == "" {
|
||||
return
|
||||
}
|
||||
// Get file names of plugin dir
|
||||
listing, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to open plugin directory:", err)
|
||||
}
|
||||
// Enumerate file names, load valid plugins
|
||||
for _, file := range listing {
|
||||
// Match name
|
||||
fileName := file.Name()
|
||||
if !strings.HasPrefix(fileName, "librcloneplugin_") {
|
||||
continue
|
||||
}
|
||||
if !strings.HasSuffix(fileName, ".so") {
|
||||
continue
|
||||
}
|
||||
// Try to load plugin
|
||||
_, err := plugin.Open(filepath.Join(dir, fileName))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to load plugin %s: %s\n",
|
||||
fileName, err)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,8 @@ package main
|
|||
import (
|
||||
_ "github.com/rclone/rclone/backend/all" // import all backends
|
||||
"github.com/rclone/rclone/cmd"
|
||||
_ "github.com/rclone/rclone/cmd/all" // import all commands
|
||||
_ "github.com/rclone/rclone/cmd/all" // import all commands
|
||||
_ "github.com/rclone/rclone/lib/plugin" // import plugins
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
Loading…
Reference in a new issue