github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/cmd/lsjson/lsjson.go (about)

     1  // Package lsjson provides the lsjson command.
     2  package lsjson
     3  
     4  import (
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"os"
     9  
    10  	"github.com/rclone/rclone/cmd"
    11  	"github.com/rclone/rclone/cmd/ls/lshelp"
    12  	"github.com/rclone/rclone/fs"
    13  	"github.com/rclone/rclone/fs/config/flags"
    14  	"github.com/rclone/rclone/fs/operations"
    15  	"github.com/spf13/cobra"
    16  )
    17  
    18  var (
    19  	opt      operations.ListJSONOpt
    20  	statOnly bool
    21  )
    22  
    23  func init() {
    24  	cmd.Root.AddCommand(commandDefinition)
    25  	cmdFlags := commandDefinition.Flags()
    26  	flags.BoolVarP(cmdFlags, &opt.Recurse, "recursive", "R", false, "Recurse into the listing", "")
    27  	flags.BoolVarP(cmdFlags, &opt.ShowHash, "hash", "", false, "Include hashes in the output (may take longer)", "")
    28  	flags.BoolVarP(cmdFlags, &opt.NoModTime, "no-modtime", "", false, "Don't read the modification time (can speed things up)", "")
    29  	flags.BoolVarP(cmdFlags, &opt.NoMimeType, "no-mimetype", "", false, "Don't read the mime type (can speed things up)", "")
    30  	flags.BoolVarP(cmdFlags, &opt.ShowEncrypted, "encrypted", "", false, "Show the encrypted names", "")
    31  	flags.BoolVarP(cmdFlags, &opt.ShowOrigIDs, "original", "", false, "Show the ID of the underlying Object", "")
    32  	flags.BoolVarP(cmdFlags, &opt.FilesOnly, "files-only", "", false, "Show only files in the listing", "")
    33  	flags.BoolVarP(cmdFlags, &opt.DirsOnly, "dirs-only", "", false, "Show only directories in the listing", "")
    34  	flags.BoolVarP(cmdFlags, &opt.Metadata, "metadata", "M", false, "Add metadata to the listing", "")
    35  	flags.StringArrayVarP(cmdFlags, &opt.HashTypes, "hash-type", "", nil, "Show only this hash type (may be repeated)", "")
    36  	flags.BoolVarP(cmdFlags, &statOnly, "stat", "", false, "Just return the info for the pointed to file", "")
    37  }
    38  
    39  var commandDefinition = &cobra.Command{
    40  	Use:   "lsjson remote:path",
    41  	Short: `List directories and objects in the path in JSON format.`,
    42  	Long: `List directories and objects in the path in JSON format.
    43  
    44  The output is an array of Items, where each Item looks like this
    45  
    46      {
    47        "Hashes" : {
    48           "SHA-1" : "f572d396fae9206628714fb2ce00f72e94f2258f",
    49           "MD5" : "b1946ac92492d2347c6235b4d2611184",
    50           "DropboxHash" : "ecb65bb98f9d905b70458986c39fcbad7715e5f2fcc3b1f07767d7c83e2438cc"
    51        },
    52        "ID": "y2djkhiujf83u33",
    53        "OrigID": "UYOJVTUW00Q1RzTDA",
    54        "IsBucket" : false,
    55        "IsDir" : false,
    56        "MimeType" : "application/octet-stream",
    57        "ModTime" : "2017-05-31T16:15:57.034468261+01:00",
    58        "Name" : "file.txt",
    59        "Encrypted" : "v0qpsdq8anpci8n929v3uu9338",
    60        "EncryptedPath" : "kja9098349023498/v0qpsdq8anpci8n929v3uu9338",
    61        "Path" : "full/path/goes/here/file.txt",
    62        "Size" : 6,
    63        "Tier" : "hot",
    64      }
    65  
    66  If ` + "`--hash`" + ` is not specified, the Hashes property will be omitted. The
    67  types of hash can be specified with the ` + "`--hash-type`" + ` parameter (which
    68  may be repeated). If ` + "`--hash-type`" + ` is set then it implies ` + "`--hash`" + `.
    69  
    70  If ` + "`--no-modtime`" + ` is specified then ModTime will be blank. This can
    71  speed things up on remotes where reading the ModTime takes an extra
    72  request (e.g. s3, swift).
    73  
    74  If ` + "`--no-mimetype`" + ` is specified then MimeType will be blank. This can
    75  speed things up on remotes where reading the MimeType takes an extra
    76  request (e.g. s3, swift).
    77  
    78  If ` + "`--encrypted`" + ` is not specified the Encrypted will be omitted.
    79  
    80  If ` + "`--dirs-only`" + ` is not specified files in addition to directories are
    81  returned
    82  
    83  If ` + "`--files-only`" + ` is not specified directories in addition to the files
    84  will be returned.
    85  
    86  If ` + "`--metadata`" + ` is set then an additional Metadata key will be returned.
    87  This will have metadata in rclone standard format as a JSON object.
    88  
    89  if ` + "`--stat`" + ` is set then a single JSON blob will be returned about the
    90  item pointed to. This will return an error if the item isn't found.
    91  However on bucket based backends (like s3, gcs, b2, azureblob etc) if
    92  the item isn't found it will return an empty directory as it isn't
    93  possible to tell empty directories from missing directories there.
    94  
    95  The Path field will only show folders below the remote path being listed.
    96  If "remote:path" contains the file "subfolder/file.txt", the Path for "file.txt"
    97  will be "subfolder/file.txt", not "remote:path/subfolder/file.txt".
    98  When used without ` + "`--recursive`" + ` the Path will always be the same as Name.
    99  
   100  If the directory is a bucket in a bucket-based backend, then
   101  "IsBucket" will be set to true. This key won't be present unless it is
   102  "true".
   103  
   104  The time is in RFC3339 format with up to nanosecond precision.  The
   105  number of decimal digits in the seconds will depend on the precision
   106  that the remote can hold the times, so if times are accurate to the
   107  nearest millisecond (e.g. Google Drive) then 3 digits will always be
   108  shown ("2017-05-31T16:15:57.034+01:00") whereas if the times are
   109  accurate to the nearest second (Dropbox, Box, WebDav, etc.) no digits
   110  will be shown ("2017-05-31T16:15:57+01:00").
   111  
   112  The whole output can be processed as a JSON blob, or alternatively it
   113  can be processed line by line as each item is written one to a line.
   114  ` + lshelp.Help,
   115  	Annotations: map[string]string{
   116  		"versionIntroduced": "v1.37",
   117  		"groups":            "Filter,Listing",
   118  	},
   119  	RunE: func(command *cobra.Command, args []string) error {
   120  		// Make sure we set the global Metadata flag too as it
   121  		// isn't parsed by cobra. We need to do this first
   122  		// before any backends are created.
   123  		ci := fs.GetConfig(context.Background())
   124  		ci.Metadata = opt.Metadata
   125  
   126  		cmd.CheckArgs(1, 1, command, args)
   127  		var fsrc fs.Fs
   128  		var remote string
   129  		if statOnly {
   130  			fsrc, remote = cmd.NewFsFile(args[0])
   131  		} else {
   132  			fsrc = cmd.NewFsSrc(args)
   133  		}
   134  		cmd.Run(false, false, command, func() error {
   135  			if statOnly {
   136  				item, err := operations.StatJSON(context.Background(), fsrc, remote, &opt)
   137  				if err != nil {
   138  					return err
   139  				}
   140  				out, err := json.MarshalIndent(item, "", "\t")
   141  				if err != nil {
   142  					return fmt.Errorf("failed to marshal list object: %w", err)
   143  				}
   144  				_, err = os.Stdout.Write(out)
   145  				if err != nil {
   146  					return fmt.Errorf("failed to write to output: %w", err)
   147  				}
   148  				fmt.Println()
   149  			} else {
   150  				fmt.Println("[")
   151  				first := true
   152  				err := operations.ListJSON(context.Background(), fsrc, remote, &opt, func(item *operations.ListJSONItem) error {
   153  					out, err := json.Marshal(item)
   154  					if err != nil {
   155  						return fmt.Errorf("failed to marshal list object: %w", err)
   156  					}
   157  					if first {
   158  						first = false
   159  					} else {
   160  						fmt.Print(",\n")
   161  					}
   162  					_, err = os.Stdout.Write(out)
   163  					if err != nil {
   164  						return fmt.Errorf("failed to write to output: %w", err)
   165  					}
   166  					return nil
   167  				})
   168  				if err != nil {
   169  					return err
   170  				}
   171  				if !first {
   172  					fmt.Println()
   173  				}
   174  				fmt.Println("]")
   175  			}
   176  			return nil
   177  		})
   178  		return nil
   179  	},
   180  }