ensync
ensync copied to clipboard
Proposal: JSON status output for `ensync sync`
UX
This output is activated by the following flag to ensync sync: --json-status-fd FD, where FD is a valid file
descriptor.
This flag will cause status messages to be output on the given file descriptor in the format described below. Other output will be unaffected.
Message format
Status messages are line-delimited JSON in the following format:
{"status_version": 1, "time": ... "type": "...", ...}
where:
"status_version"is always 1 (and may be incremented to reflect breaking changes to the status format)."time"is the time when the message was emitted, as a fractional number of seconds since the UNIX epoch."type"is a string indicating the type of message.- Other fields may be set depending on
"type".
Message types
The following types of messages may be emitted. New types may be added or new fields may be added to existing types in a future version of this format without "status_version" being incremented. However, changed/removed fields will result in "status_version" being incremented.
"type": "sync_started"
{..., "type": "sync_started"}
Output when the sync begins.
"type": "sync_finished"
{..., "type": "sync_started"}
Output when the sync finishes successfully.
"type": "sync_failed"
{..., "type": "sync_failed", "error_message": ...}
Output when the sync as a whole fails (connection failure, etc.). "error_message" should contain a human-readable error message.
"type": "sync_conflict"
{..., "type": "sync_conflict", "path": ..., "conflict_type": ..., "conflict_reconciliation": ...}
Output when a path is in conflict.
"path" is the path to the affected file/directory, relative to the sync root.
"conflict_type" is one of:
"edit_local_delete_remote": path was edited locally but deleted on the remote."edit_remote_delete_local": path was edited on the remote but deleted locally."edit_edit": path was edited both locally and on the remote.
and "conflict_reconciliation" is one of
"unsynced": files are out of sync but nothing is being done. Common when a path is ignored."irreconcilable": files are out of sync but ensync is forbidden from fixing the situation. Usually due to sync rules."use_local": the local version is being used."use_remote": the remote version is being used."split_local": the local and remote versions have diverged, and the local version is being renamed."split_remote": the local and remote versions have diverged, and the remote version is being renamed.
"type": "sync_create"
{..., "type": "sync_create", "side": ..., "path": ..., "info": ...}
Output when a file/directory is created.
"side" is one of "remote" or "local".
"path" is the path to the affected file/directory, relative to the sync root.
"info" is the PATH_INFO structure described below.
"type": "sync_update"
{..., "type": "sync_update", "side": ..., "path": ..., "update_old_info": ..., "update_new_info": ...}
Output when a path is updated.
"side" is one of "remote" or "local".
"path" is the path to the affected file/directory, relative to the sync root.
"update_old_info" and "update_new_info" are the PATH_INFO structure described below.
"type": "sync_rename"
{..., "type": "sync_rename", "side": ...,"path": ..., "rename_new_name": ...}
Output when a path is updated.
"side" is one of "remote" or "local".
"path" is the path to the affected file/directory, relative to the sync root.
"rename_new_name" is the new name of the path ("path" is the old).
"type": "sync_remove"
{..., "type": "sync_remove", "side": ..., "path": ..., "info": ...}
Output when a path is removed.
"side" is one of "remote" or "local".
"path" is the path to the affected file/directory, relative to the sync root.
"info" is the PATH_INFO structure described below.
"type": "sync_remove_recursively"
{..., "type": "sync_remove_recursively", "side": ..., "path": ...}
Output when a path and all its descendants are removed.
"side" is one of "remote" or "local".
"path" is the path to the affected directory, relative to the sync root.
"type": "sync_remove_directory"
{..., "type": "sync_remove_directory", "side": ..., "path": ...}
Output when a directory is removed.
"side" is one of "remote" or "local".
"path" is the path to the affected directory, relative to the sync root.
"type": "sync_error"
{..., "type": "sync_error", "side": ..., "path": ..., "error_message": ...}
Output when an error occurs for a path.
"side" is one of "remote" or "local".
"path" is the path to the affected directory, relative to the sync root.
"error_message" is a human-readable error message.
PATH_INFO
This structure contains details on the contents of a given path. It is contained in several
different kinds of "sync_path" messages.
It has the form:
{"type": ..., ...}
Where "type" is one of the values described below, each with a different shape.
"type": "directory"
{"type": "directory", "mode": ...}
"mode" is a UNIX-style mode, encoded in decimal. (e.g., mode 755 would be encoded as 493.)
"type": "file"
{"type": "file", "mode": ..., "size": ..., "modified_time": ...}
"mode" is a UNIX-style mode, encoded in decimal. (e.g., mode 755 would be encoded as 493.)
"size" is the size of the file in bytes.
"modified_time" is the modification time of the file as fractional seconds since the UNIX epoch.
"type": "symlink"
{"type": "file", "target": ...}
"target" is the target of the symbolic link.
"type": "special"
{"type": "special"}
Any other type of non-regular file.
What does this comment mean?
When performing a recursive deletion, the reconciler finishes each directory level by blindly rmdiring the directory on both sides, so if the file counters were updated accordingly, it would show deletions on a side that didn't actually have the directory.
"time"is the time when the message was emitted, as a fractional number of seconds since the UNIX epoch.
ISO-8601 would probably be more appropriate here. I think that's what chrono's serde integration does anyway. Same with modified-time later on.
Otherwise this looks like a sound plan to me.