Merge pull request #4664 from MichaelEischer/ls-unified-json-output

ls: include standard `message_type` field in output
This commit is contained in:
Michael Eischer 2024-02-18 15:47:41 +00:00 committed by GitHub
commit 80754dbf0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 81 additions and 74 deletions

View File

@ -0,0 +1,8 @@
Enhancement: `ls` uses `message_type` field to distinguish JSON messages
The `ls` command was the only command that used the `struct_type` field to determine
the message type in the JSON output format. Now, the JSON output of the
`ls` command also includes the `message_type`. The `struct_type` field is
still included, but it deprecated.
https://github.com/restic/restic/pull/4664

View File

@ -83,16 +83,18 @@ type jsonLsPrinter struct {
func (p *jsonLsPrinter) Snapshot(sn *restic.Snapshot) { func (p *jsonLsPrinter) Snapshot(sn *restic.Snapshot) {
type lsSnapshot struct { type lsSnapshot struct {
*restic.Snapshot *restic.Snapshot
ID *restic.ID `json:"id"` ID *restic.ID `json:"id"`
ShortID string `json:"short_id"` ShortID string `json:"short_id"`
StructType string `json:"struct_type"` // "snapshot" MessageType string `json:"message_type"` // "snapshot"
StructType string `json:"struct_type"` // "snapshot", deprecated
} }
err := p.enc.Encode(lsSnapshot{ err := p.enc.Encode(lsSnapshot{
Snapshot: sn, Snapshot: sn,
ID: sn.ID(), ID: sn.ID(),
ShortID: sn.ID().Str(), ShortID: sn.ID().Str(),
StructType: "snapshot", MessageType: "snapshot",
StructType: "snapshot",
}) })
if err != nil { if err != nil {
Warnf("JSON encode failed: %v\n", err) Warnf("JSON encode failed: %v\n", err)
@ -121,7 +123,8 @@ func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
AccessTime time.Time `json:"atime,omitempty"` AccessTime time.Time `json:"atime,omitempty"`
ChangeTime time.Time `json:"ctime,omitempty"` ChangeTime time.Time `json:"ctime,omitempty"`
Inode uint64 `json:"inode,omitempty"` Inode uint64 `json:"inode,omitempty"`
StructType string `json:"struct_type"` // "node" MessageType string `json:"message_type"` // "node"
StructType string `json:"struct_type"` // "node", deprecated
size uint64 // Target for Size pointer. size uint64 // Target for Size pointer.
}{ }{
@ -137,6 +140,7 @@ func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
AccessTime: node.AccessTime, AccessTime: node.AccessTime,
ChangeTime: node.ChangeTime, ChangeTime: node.ChangeTime,
Inode: node.Inode, Inode: node.Inode,
MessageType: "node",
StructType: "node", StructType: "node",
} }
// Always print size for regular files, even when empty, // Always print size for regular files, even when empty,

View File

@ -87,11 +87,11 @@ var lsTestNodes = []lsTestNode{
func TestLsNodeJSON(t *testing.T) { func TestLsNodeJSON(t *testing.T) {
for i, expect := range []string{ for i, expect := range []string{
`{"name":"baz","type":"file","path":"/bar/baz","uid":10000000,"gid":20000000,"size":12345,"permissions":"----------","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`, `{"name":"baz","type":"file","path":"/bar/baz","uid":10000000,"gid":20000000,"size":12345,"permissions":"----------","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","message_type":"node","struct_type":"node"}`,
`{"name":"empty","type":"file","path":"/foo/empty","uid":1001,"gid":1001,"size":0,"permissions":"----------","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`, `{"name":"empty","type":"file","path":"/foo/empty","uid":1001,"gid":1001,"size":0,"permissions":"----------","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","message_type":"node","struct_type":"node"}`,
`{"name":"link","type":"symlink","path":"/foo/link","uid":0,"gid":0,"mode":134218239,"permissions":"Lrwxrwxrwx","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`, `{"name":"link","type":"symlink","path":"/foo/link","uid":0,"gid":0,"mode":134218239,"permissions":"Lrwxrwxrwx","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","message_type":"node","struct_type":"node"}`,
`{"name":"directory","type":"dir","path":"/some/directory","uid":0,"gid":0,"mode":2147484141,"permissions":"drwxr-xr-x","mtime":"2020-01-02T03:04:05Z","atime":"2021-02-03T04:05:06.000000007Z","ctime":"2022-03-04T05:06:07.000000008Z","struct_type":"node"}`, `{"name":"directory","type":"dir","path":"/some/directory","uid":0,"gid":0,"mode":2147484141,"permissions":"drwxr-xr-x","mtime":"2020-01-02T03:04:05Z","atime":"2021-02-03T04:05:06.000000007Z","ctime":"2022-03-04T05:06:07.000000008Z","message_type":"node","struct_type":"node"}`,
`{"name":"sticky","type":"dir","path":"/some/sticky","uid":0,"gid":0,"mode":2161115629,"permissions":"dugtrwxr-xr-x","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`, `{"name":"sticky","type":"dir","path":"/some/sticky","uid":0,"gid":0,"mode":2161115629,"permissions":"dugtrwxr-xr-x","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","message_type":"node","struct_type":"node"}`,
} { } {
c := lsTestNodes[i] c := lsTestNodes[i]
buf := new(bytes.Buffer) buf := new(bytes.Buffer)

View File

@ -12,7 +12,6 @@ import (
"testing" "testing"
"time" "time"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/repository" "github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic" "github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test" rtest "github.com/restic/restic/internal/test"
@ -160,11 +159,6 @@ func TestMount(t *testing.T) {
t.Skip("Skipping fuse tests") t.Skip("Skipping fuse tests")
} }
debugEnabled := debug.TestLogToStderr(t)
if debugEnabled {
defer debug.TestDisableLog(t)
}
env, cleanup := withTestEnvironment(t) env, cleanup := withTestEnvironment(t)
// must list snapshots more than once // must list snapshots more than once
env.gopts.backendTestHook = nil env.gopts.backendTestHook = nil

View File

@ -75,9 +75,6 @@ Several commands, in particular long running ones or those that generate a large
use a format also known as JSON lines. It consists of a stream of new-line separated JSON use a format also known as JSON lines. It consists of a stream of new-line separated JSON
messages. You can determine the nature of the message using the ``message_type`` field. messages. You can determine the nature of the message using the ``message_type`` field.
As an exception, the ``ls`` command uses the field ``struct_type`` instead.
backup backup
------ ------
@ -420,63 +417,67 @@ As an exception, the ``struct_type`` field is used to determine the message type
snapshot snapshot
^^^^^^^^ ^^^^^^^^
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``struct_type``| Always "snapshot" | | ``message_type`` | Always "snapshot" |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``time`` | Timestamp of when the backup was started | | ``struct_type`` | Always "snapshot" (deprecated) |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``parent`` | ID of the parent snapshot | | ``time`` | Timestamp of when the backup was started |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``tree`` | ID of the root tree blob | | ``parent`` | ID of the parent snapshot |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``paths`` | List of paths included in the backup | | ``tree`` | ID of the root tree blob |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``hostname`` | Hostname of the backed up machine | | ``paths`` | List of paths included in the backup |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``username`` | Username the backup command was run as | | ``hostname`` | Hostname of the backed up machine |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``uid`` | ID of owner | | ``username`` | Username the backup command was run as |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``gid`` | ID of group | | ``uid`` | ID of owner |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``excludes`` | List of paths and globs excluded from the backup | | ``gid`` | ID of group |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``tags`` | List of tags for the snapshot in question | | ``excludes`` | List of paths and globs excluded from the backup |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``id`` | Snapshot ID | | ``tags`` | List of tags for the snapshot in question |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``short_id`` | Snapshot ID, short form | | ``id`` | Snapshot ID |
+----------------+--------------------------------------------------+ +------------------+--------------------------------------------------+
| ``short_id`` | Snapshot ID, short form |
+------------------+--------------------------------------------------+
node node
^^^^ ^^^^
+-----------------+--------------------------+ +------------------+----------------------------+
| ``struct_type`` | Always "node" | | ``message_type`` | Always "node" |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``name`` | Node name | | ``struct_type`` | Always "node" (deprecated) |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``type`` | Node type | | ``name`` | Node name |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``path`` | Node path | | ``type`` | Node type |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``uid`` | UID of node | | ``path`` | Node path |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``gid`` | GID of node | | ``uid`` | UID of node |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``size`` | Size in bytes | | ``gid`` | GID of node |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``mode`` | Node mode | | ``size`` | Size in bytes |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``atime`` | Node access time | | ``mode`` | Node mode |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``mtime`` | Node modification time | | ``atime`` | Node access time |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``ctime`` | Node creation time | | ``mtime`` | Node modification time |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``inode`` | Inode number of node | | ``ctime`` | Node creation time |
+-----------------+--------------------------+ +------------------+----------------------------+
| ``inode`` | Inode number of node |
+------------------+----------------------------+
restore restore