-
Notifications
You must be signed in to change notification settings - Fork 216
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>TransferPluginextendingorg.syncany.plugins.transfer.TransferPlugin - Class
org.syncany.plugins.<plugin-id>.<camel-plugin-id>TransferSettingsextendingorg.syncany.plugins.transfer.TransferSettings - Class
org.syncany.connection.plugins.<plugin-id>.<camel-plugin-id>TransferManagerextendingorg.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:namecan be used to change the field's name within the persisted XML file. -
required:requiredvalues 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: Lowerordered 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 markedsensitivewill 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 settingsingularto 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. Thereforedescriptioncan 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.propertiescontainingpluginId,pluginName,pluginVersion,pluginDate,pluginAppMinVersionandpluginRelease - JAR Manifest (MANIFEST.MF) containing the same information:
Plugin-Id,Plugin-Name,Plugin-Version,Plugin-Date,Plugin-App-Min-VersionandPlugin-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.gradlesettings, 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