This is an appendix to the external special remote protocol.
Some special remotes interface to a key/value datastore using keys that are eg hashes, and it won't make sense for them to implement any of this.
When a special remote interfaces with something that looks like a directory of files, it can implement either or both of the interfaces described here.
The export interface can be implemented to allow the git-annex-export command to be used to store file trees on the special remote.
The import interface can be implemented to allow the git-annex-import command to be used to import file trees from the special remote that are written by some other tool or process.
Note that, when a special remote implements both interfaces, the user will
need to choose at initremote time whether to use importtree=yes or
exporttree=yes. They won't be allowed to use both, since this interface
is not designed to safely allow import and export with the same special
remote.
export interface
git-annex will use this when the special remote is initialized with exporttree=yes and indicates that it supports exports.
These are requests git-annex sends to the special remote program.
Once the special remote has finished performing a request, it
should send one of the listed replies. Or, if it does not support
a request, it can reply with UNSUPPORTED-REQUEST.
EXPORTSUPPORTED
Used to check if a special remote supports exports. Note that this request may be made before or afterPREPARE.EXPORTSUPPORTED-SUCCESS
Indicates that it makes sense to export to this special remote.EXPORTSUPPORTED-FAILURE
Indicates that it does not make sense to export to this special remote.
EXPORT Name
Comes immediately before each of the following requests (except forREMOVEEXPORTDIRECTORY), specifying the name of the exported file. It will be in the form of a relative path, and may contain path separators, whitespace, and other special characters.
No response is made to this message.
Note that old versions of git-annex had a bug that sometimes prevented sendingEXPORT. To avoid being used with such a buggy version of git-annex, sendVERSION 2.TRANSFEREXPORT STORE|RETRIEVE Key File
Requests the transfer of a File on local disk to or from the previously providedEXPORTName on the special remote.
Note that it's important that, while a file is being stored,CHECKPRESENTEXPORTnot indicate it's present until all the data has been transferred.
While the transfer is running, the remote can send any number ofPROGRESSmessages. Once the transfer is complete, it finishes by sending one of these replies:TRANSFER-SUCCESS STORE|RETRIEVE Key
Indicates the transfer completed successfully.TRANSFER-FAILURE STORE|RETRIEVE Key ErrorMsg
Indicates the transfer failed.TRANSFER-RETRIEVE-URL Key Url
Rather than the special remote downloading content from an url itself, this lets it offload that work to git-annex. This response is a protocol extension; it's only safe to send it to git-annex after it sent anEXTENSIONSthat includedTRANSFER-RETRIEVE-URL.DELEGATE type=value [params]
Delegate this request to a different type of special remote. See delegate appendix.
CHECKPRESENTEXPORT Key
Requests the remote to check if the previously providedEXPORTName is present in it.CHECKPRESENT-SUCCESS Key
Indicates that a content has been positively verified to be present in the remote.CHECKPRESENT-FAILURE Key
Indicates that a contents has been positively verified to not be present in the remote.CHECKPRESENT-UNKNOWN Key ErrorMsg
Indicates that it is not currently possible to verify if content is present in the remote. (Perhaps the remote cannot be contacted.)CHECKPRESENT-URL Key Url
Rather than the special remote checking an url itself, this lets it offload that work to git-annex. This response is a protocol extension; it's only safe to send it to git-annex after it sent anEXTENSIONSthat includedCHECKPRESENT-URL.DELEGATE type=value [params]
Delegate this request to a different type of special remote. See delegate appendix.
REMOVEEXPORT Key
Requests the remote to remove content stored byTRANSFEREXPORTwith the previously providedEXPORTName.REMOVE-SUCCESS Key
Indicates the content has been removed from the remote. May be returned when the content was already not present.REMOVE-FAILURE Key ErrorMsg
Indicates that the content was unable to be removed from the remote.DELEGATE type=value [params]
Delegate this request to a different type of special remote. See delegate appendix.
REMOVEEXPORTDIRECTORY Directory
Requests the remote remove an exported directory.
If the remote does not use directories, orREMOVEEXPORTcleans up directories that are empty, this does not need to be implemented.
The directory will be in the form of a relative path, and may contain path separators, whitespace, and other special characters.
Typically the directory will be empty, but it could possibly contain files or other directories, and it's ok to remove those, but better to avoid doing so.REMOVEEXPORTDIRECTORY-SUCCESS
Indicates that aREMOVEEXPORTDIRECTORYwas done successfully.REMOVEEXPORTDIRECTORY-FAILURE
Indicates that aREMOVEEXPORTDIRECTORYfailed for whatever reason. Should not be returned if the directory did not exist.DELEGATE type=value [params]
Delegate this request to a different type of special remote. See delegate appendix.
RENAMEEXPORT Key NewName
Requests the remote rename a file stored on it from the previously providedEXPORTName to the NewName. Remotes that support exports but not renaming do not need to implement this.RENAMEEXPORT-SUCCESS Key
Indicates that aRENAMEEXPORTwas done successfully.RENAMEEXPORT-FAILURE Key
Indicates that aRENAMEEXPORTfailed for whatever reason.DELEGATE type=value [params]
Delegate this request to a different type of special remote. See delegate appendix.
import interface
git-annex will use this interface when the special remote is initialized with importtree=yes and indicates that it supports imports.
git-annex version 10.20260717 was the first to support this.
content identifiers
The special remote needs to have some way to identify a particular version of a file. This is called a ContentIdentifier. A good ContentIdentifier needs to:
- Be stable, so when a file has not changed, its content identifier remains the same.
- Change when a file is modified.
- Be as unique as possible, but not necessarily fully unique. A hash of the content would be ideal. A (size, mtime, inode) tuple is as good a content identifier as git uses in its index. A (size, mtime) tuple will detect most modifications to files, and is usually good enough.
- Be reasonably short, since it will be stored in the git-annex branch.
It's up to the implementor of a external special remote program what to use for their ContentIdentifier, but not meeting those criteria will lead to unhappy users, and it's better not to implement this interface if you can't do it well.
protocol messages
These are requests that git-annex sends to the special remote
program. Once the special remote has finished performing a request,
it should send one of the listed replies. Or, if it does not
support a request, it can reply with UNSUPPORTED-REQUEST.
IMPORTSUPPORTED
Used to check if a special remote supports imports. Note that this request may be made before or afterPREPARE.IMPORTSUPPORTED-SUCCESS
Indicates that it makes sense to import from this special remote.IMPORTSUPPORTED-FAILURE
Indicates that it does not make sense to import from this special remote.IMPORTREQUIREDIndicates that this special remote only supports imports. It cannot be used for exports, or used as a key/value store. This allows responding toTRANSFER,CHECKPRESENT, andREMOVEwithUNSUPPORTED-REQUEST. When initializing such a special remote, the user will be required to specify theexporttree=yesparameter.
LISTIMPORTABLECONTENTS
Used to get a list of all the files that are stored in the special remote. A block of responses can be made to this, which must always end withLISTIMPORTABLECONTENTS-SUCCESSor `LISTIMPORTABLECONTENTS-FAILURE.IMPORTABLECONTENT Size Name
A file stored in the special remote. The Size is its size in bytes. The Name is the name of the file on the remote, in the form of a relative path, and may contain path separators, whitespace, and other special characters.
Always followed byIMPORTABLECONTENTIDENTIFIER.IMPORTABLECONTENTIDENTIFIER ContentIdentifier
Provide the ContentIdentifier for the previousCONTENT.LISTIMPORTABLECONTENTS-SUCCESS
Indicates the end of the block of responses and success.LISTIMPORTABLECONTENTS-FAILURE ErrorMsg
Indicates the end of the block of responses (which may be empty) and failure.DELEGATE type=value [params]
Delegate this request to a different type of special remote. See delegate appendix.
IMPORT Name
Comes before each of the following requests, specifying the name of the file on the remote. It will be in the form of a relative path, and may contain path separators, whitespace, and other special characters.
No response is made to this message.RETRIEVEIMPORT File
Retrieves the content of a file with the previously providedIMPORTName from the special remote to the File on local disk.
Note that the special remote can sendDOWNLOAD-URLmessages without negotiating support for it in the protocol, because versions of git-annex that support this also supportDOWNLOAD-URL.
While the transfer is running, the remote can send any number ofPROGRESSmessages. Once the transfer is complete, it finishes by sending one of these replies:RETRIEVEIMPORT-SUCCESSIndicates that the retrieve was successful.RETRIEVEIMPORT-FAILURE ErrorMsg
Indicates the retrieve failed.RETRIEVEIMPORT-URL Url
Rather than the special remote downloading content from an url itself, this lets it offload that work to git-annex.DELEGATE type=value [params]
Delegate this request to a different type of special remote. See delegate appendix.
CHECKPRESENTIMPORT Key
Requests the remote to check if the previously providedIMPORTName is present in it.CHECKPRESENT-SUCCESS Key
Indicates that a content has been positively verified to be present in the remote.CHECKPRESENT-FAILURE Key
Indicates that a content has been positively verified to not be present in the remote.CHECKPRESENT-UNKNOWN Key ErrorMsg
Indicates that it is not currently possible to verify if content is present in the remote. (Perhaps the remote cannot be contacted.)CHECKPRESENT-URL Key Url
Rather than the special remote checking an url itself, this lets it offload that work to git-annex.DELEGATE type=value [params]
Delegate this request to a different type of special remote. See delegate appendix.
IMPORTKEY Size ContentIdentifier
Requests the remote generate a git-annex key for content stored on it without downloading that content.
This request is a protocol extension and will only be sent if the special remote sent anEXTENSIONSthat includedIMPORTKEY.
Implementing this allows usinggit-annex import --no-contentfrom the remote. The remote can generate any type of git-annex key that uses a checksum. For example, if a cloud storage service allows querying for a md5, key, it's ok to generate a MD5 key. To generate the key, see key format.
The previously providedIMPORTName specifies which file on the remote to generate the key for.
The Size is provided because the key should include the size of the file.
The ContentIdentifier is provided in case it can be used to avoid extra work in determining the key. For example, if a remote uses a md5 as the ContentIdentifier inLISTIMPORTABLECONTENTS, it can reuse the md5 to generate the key. It is not necessary to guarantee that the file on the remote still has the same ContentIdentifier.IMPORTKEY-SUCCESS Key
Responding with a key.IMPORTKEY-FAILURE ErrorMsg
Indicates that it was not possible to import a key. (Perhaps because the remote cannot be contacted.)IMPORTKEY-SKIP
This makes the file not be included in the imported tree.DELEGATE type=value [params]
Delegate this request to a different type of special remote. See delegate appendix.
import example
The protocol starts off with VERSION etc as usual, and then git-annex asks the special remote if it supports export and import. In this example it supports both:
VERSION 1
EXTENSIONS INFO
EXTENSIONS
PREPARE
EXPORTSUPPORTED
EXPORTSUPPORTED-SUCCESS
IMPORTSUPPORTED
IMPORTSUPPORTED-SUCCESS
git-annex asks for a list of files stored in the special remote:
LISTIMPORTABLECONTENTS
Which responds:
IMPORTABLECONTENT 100 foo
IMPORTABLECONTENTIDENTIFIER 100 48511528411921470
IMPORTABLECONTENT 200 bar
IMPORTABLECONTENTIDENTIFIER 200 48511528411963410
IMPORTABLECONTENTS-SUCCESS
Next git-annex asks for the content of a file to be retrieved.
IMPORT foo
RETRIEVEIMPORT tmpfile
If the file no longer exists, the response would be:
RETRIEVEIMPORT-FAILURE file not found
If the file exists, the response would be:
RETRIEVEIMPORT-SUCCESS
What if the file exists but has been modified in the time since LISTIMPORTABLECONTENTS? The external special remote still retrieves it. git-annex will then notice that the hash doesn't match.
@mih it's still only a draft. See add import tree to external special remote protocol
What I would like to do is work on implementing it in concert with someone making a special remote that uses it, so we can find the pain points and iterate a bit and hopefully improve it.
I have a use case for the importree protocol extensions:
I would like to ingest photos and documents from my familys iCloud share.
I am planning on using git-annex with the new rclone special remote to do so. rclone is just in the process of adding support for a new iCloud drive/photos remote to make it feasible.
The missing piece is that we can not yet import/sync a tree of files from rclone into my annex.
@joeyh.name I would be quite interested to work with you on getting this supported.
@stv0g I'm pretty busy with other features, on the other hand implementing the git-annex side of this would not really be that hard. It's making sure that git-annex doesn't encourage lots of unsafe things to be built with the export/import interface that seems hard to me.
Would you need the full export/import interface though? importtree only remotes would be enough if you only want to import, and it avoids the tricky question of how to avoid data loss due to overwriting a modified file in your implementation of STOREEXPORTEXPECTED.
On the other hand, if rclone provides something that can be used as a good ContentIdentifier, and has a way to avoid a store overwriting a modified file, it would be great to have this interface.