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

     1  // Package size provides the size command.
     2  package size
     3  
     4  import (
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"os"
     9  	"strconv"
    10  
    11  	"github.com/rclone/rclone/cmd"
    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 jsonOutput bool
    19  
    20  func init() {
    21  	cmd.Root.AddCommand(commandDefinition)
    22  	cmdFlags := commandDefinition.Flags()
    23  	flags.BoolVarP(cmdFlags, &jsonOutput, "json", "", false, "Format output as JSON", "")
    24  }
    25  
    26  var commandDefinition = &cobra.Command{
    27  	Use:   "size remote:path",
    28  	Short: `Prints the total size and number of objects in remote:path.`,
    29  	Long: `
    30  Counts objects in the path and calculates the total size. Prints the
    31  result to standard output.
    32  
    33  By default the output is in human-readable format, but shows values in
    34  both human-readable format as well as the raw numbers (global option
    35  ` + "`--human-readable`" + ` is not considered). Use option ` + "`--json`" + `
    36  to format output as JSON instead.
    37  
    38  Recurses by default, use ` + "`--max-depth 1`" + ` to stop the
    39  recursion.
    40  
    41  Some backends do not always provide file sizes, see for example
    42  [Google Photos](/googlephotos/#size) and
    43  [Google Docs](/drive/#limitations-of-google-docs).
    44  Rclone will then show a notice in the log indicating how many such
    45  files were encountered, and count them in as empty files in the output
    46  of the size command.
    47  `,
    48  	Annotations: map[string]string{
    49  		"versionIntroduced": "v1.23",
    50  		"groups":            "Filter,Listing",
    51  	},
    52  	Run: func(command *cobra.Command, args []string) {
    53  		cmd.CheckArgs(1, 1, command, args)
    54  		fsrc := cmd.NewFsSrc(args)
    55  		cmd.Run(false, false, command, func() error {
    56  			var err error
    57  			var results struct {
    58  				Count    int64 `json:"count"`
    59  				Bytes    int64 `json:"bytes"`
    60  				Sizeless int64 `json:"sizeless"`
    61  			}
    62  
    63  			results.Count, results.Bytes, results.Sizeless, err = operations.Count(context.Background(), fsrc)
    64  			if err != nil {
    65  				return err
    66  			}
    67  			if results.Sizeless > 0 {
    68  				fs.Logf(fsrc, "Size may be underestimated due to %d objects with unknown size", results.Sizeless)
    69  			}
    70  			if jsonOutput {
    71  				return json.NewEncoder(os.Stdout).Encode(results)
    72  			}
    73  			count := strconv.FormatInt(results.Count, 10)
    74  			countSuffix := fs.CountSuffix(results.Count).String()
    75  			if count == countSuffix {
    76  				fmt.Printf("Total objects: %s\n", count)
    77  			} else {
    78  				fmt.Printf("Total objects: %s (%s)\n", countSuffix, count)
    79  			}
    80  			fmt.Printf("Total size: %s (%d Byte)\n", fs.SizeSuffix(results.Bytes).ByteUnit(), results.Bytes)
    81  			if results.Sizeless > 0 {
    82  				fmt.Printf("Total objects with unknown size: %s (%d)\n", fs.CountSuffix(results.Sizeless), results.Sizeless)
    83  			}
    84  			return nil
    85  		})
    86  	},
    87  }