-
Notifications
You must be signed in to change notification settings - Fork 213
Plugin development
Plugins managed by the Syncany team are hosted on the Syncany organziation space. To create a new plugin, I'd suggest you copy an existing plugin and start from there. If you want to improve an existing plugin, simply check out the plugin like this:
git clone [email protected]:syncany/syncany-plugin-<plugin>.git
cd syncany-plugin-<plugin>
gradle eclipse
This sets Eclipse and lets you import the plugin as an Eclipse project. See the building wiki page for more details. Note that gradle is not included in the plugin repositories. To obtain it, you can either copy or symlink it from core/, or ensure you have a system-wide install of gradle.
If Eclipse does not find your nested projects you might need to generate Eclipse project files for the Syncany core project.
cd core
./gradlew eclipse
As of now, you need to create the following classes/files to create a new plugin. Note that this might change in future versions, but we try to keep it as stable as possible. <plugin-id> is a lower case identifier of your plugin, e.g. sftp, s3, ftp. <camel-plugin-id> is the same plugin identifier, but written as with a starting upper case letter, e.g. Sftp, S3 or Ftp. No capitals other than the first letter are allowed.
- Package
org.syncany.plugins.<plugin-id>
- Class
org.syncany.plugins.<plugin-id>.<camel-plugin-id>TransferPlugin
extendingorg.syncany.plugins.transfer.TransferPlugin
- Class
org.syncany.plugins.<plugin-id>.<camel-plugin-id>TransferSettings
extendingorg.syncany.plugins.transfer.TransferSettings
- Class
org.syncany.connection.plugins.<plugin-id>.<camel-plugin-id>TransferManager
extendingorg.syncany.plugins.transfer.AbstractTransferManager
Every plugin has a TransferManager
and TransferSettings
. TransferManager
is implementing the the communication with the intended storage backend. Some transfer plugins might need to store settings like credentials or file paths. This can be done by reflecting those settings in a TransferSettings
object which is stored by Syncany in XML representation within a repository. Supported values to store are String, Integer, Boolean, File and TransferSettings
again. One can either store a concrete TransferSettings
object like LocalTransferSettings
or use TransferSettings
to provide a wildcard transfer settings object. In the later case Syncany will ask a user which transfer plugin (from all installed plugins except the current one) he wants to use while initializing your plugin.
Syncany uses the simpleframework to persist TransferSettings
objects.
@Element(name = "accessToken", required = true)
@Setup(order = 1, sensitive = true, singular = true, description = "Access token", callback = DropboxAuthPluginOptionCallback.class, converter = DropboxAuthPluginOptionConverter.class)
@Encrypted
public String accessToken;
All fields marked with the org.simpleframework.xml.Element
annotation will be stored on disk, i.e. this are the persisted plugin values (username, passwords, ...).
-
name
:name
can be used to change the field's name within the persisted XML file. -
required
:required
values cannot be skipped during initialization.
The org.syncany.plugins.transfer.Setup
annotation is used to change syncany's behaviour during plugin initialization. Fallback values will be used if the fully optional annotation is omitted.
-
order
: Lowerorder
ed values will be formerly asked during the query process. Please note that if an order value is assigned multiple times, ordering cannot be guaranteed. -
sensitive
: Fields markedsensitive
will not be outputted when a user enters character (recommended for passwords or similar field types). -
singular
: If a user reviews values during initialization Syncany pre fills the fields with the previously entered value. This can be disabled by settingsingular
to true. This might be needed for some oauth based plugins if a token is only for one-time usage. -
description
: Usually, syncany uses the field's name during initialization which might be cryptic in some cases. Thereforedescription
can overwrite this behaviour allowing to use a more meaningful instruction. -
callback
: A callback is a class implementingorg.syncany.plugins.transfer.TransferPluginOptionCallback
.String preQueryCallback()
returns a string which is printed before before a user enters a value.String postQueryCallback(String optionValue)
is called after a user has entered the setting with the entered setting being an argument. It also returns a string which is shown to a user. -
converter
: Sometimes it is needed that an entered setting value is converted. For instance, the dropbox plugin uses this method to extract the access token from the received authorisation token. Such a converter has to implementorg.syncany.plugins.transfer.TransferPluginOptionConverter
. ItsString convert(String input)
method is then called beforeorg.syncany.plugins.transfer.TransferPluginOptionCallback#postQueryCallback
.
org.syncany.plugins.transfer.Encrypted
can be used to encrypt a field value when it's persisted to disk using a machine dependent key. Therefore repository configurations with @Encrypted
cannot be copied between different computers.
Finally, Syncany supports to mark different methods with the org.simpleframework.xml.core.Validate
annotation. Such methods are called once all settings have been entered by user. They can be used to actually test the entered settings against different, developer defined constraints. If a constraint is breached, raising a org.syncany.plugins.transfer.StorageException
with a significant error message can be used to trigger a restart of the query process.
- Properties file at
org/syncany/connection/plugins/<plugin-id>/plugin.properties
containingpluginId
,pluginName
,pluginVersion
,pluginDate
,pluginAppMinVersion
andpluginRelease
- JAR Manifest (MANIFEST.MF) containing the same information:
Plugin-Id
,Plugin-Name
,Plugin-Version
,Plugin-Date
,Plugin-App-Min-Version
andPlugin-Release
.
./gradlew pluginJar
The plugins include the main project tree in the core/
folder. This folder is managed through git subtree (also: a git subtree tutorial). Here are a few useful commands to manage this folder.
Initially (for new plugins only), you need to create an empty core/
folder and add the subtree for the core:
git remote add coreorigin -f [email protected]:syncany/syncany.git (note the -f)
git subtree add --prefix=core coreorigin/develop --squash (note the --squash)
Once this is done, the core/
folder contains the entire main project. It won't update/pull anything automatically. This has to be done manually (whenever needed) using the following command:
git fetch coreorigin
git subtree pull --prefix=core coreorigin develop --squash
If the plugin needs to change things in the core/
(aka the main project), just commit normally to the plugin, e.g. change code inside core/...; To commit/push back to the main project, do that:
git commit ...
git subtree push --prefix=core coreorigin develop
Further git subtree
resources: http://lostechies.com/johnteague/2014/04/04/using-git-subtrees-to-split-a-repository/
To automatically build a plugin, upload it to the Syncany server and register it in the plugin API (sy plugin list
). A few steps are necessary:
Copy .travis.yml from another plugin
To automatically upload your plugin to the Syncany server, please contact binwiederhier to give you an API key. If you have them, do that:
- Update the environment variables (
- secure: ...
in .travis.yml):
travis encrypt "SYNCANY_API_KEY=..."
- Create
src/main/resources/org/syncany/connection/plugins/<plugin>/plugin.properties
- Update
build.gradle
settings, esp. dependencies to include in JAR (pluginjar
)
If you alter a plugin many times and want to test your changes, you can run the following command to install your plugin:
gradle clean pluginJar; sy plugin remove <plugin>; sy plugin install build/libs/*.jar