1package cmd
 2
 3import (
 4	"fmt"
 5
 6	"github.com/charmbracelet/soft-serve/git"
 7	"github.com/dustin/go-humanize"
 8	"github.com/spf13/cobra"
 9)
10
11// treeCommand returns a command that list file or directory at path.
12func treeCommand() *cobra.Command {
13	cmd := &cobra.Command{
14		Use:               "tree REPOSITORY [REFERENCE] [PATH]",
15		Short:             "Print repository tree at path",
16		Args:              cobra.RangeArgs(1, 3),
17		PersistentPreRunE: checkIfReadable,
18		RunE: func(cmd *cobra.Command, args []string) error {
19			cfg, _ := fromContext(cmd)
20			rn := args[0]
21			path := ""
22			ref := ""
23			switch len(args) {
24			case 2:
25				path = args[1]
26			case 3:
27				ref = args[1]
28				path = args[2]
29			}
30			rr, err := cfg.Backend.Repository(rn)
31			if err != nil {
32				return err
33			}
34
35			r, err := rr.Open()
36			if err != nil {
37				return err
38			}
39
40			if ref == "" {
41				head, err := r.HEAD()
42				if err != nil {
43					if bs, err := r.Branches(); err != nil && len(bs) == 0 {
44						return fmt.Errorf("repository is empty")
45					}
46					return err
47				}
48
49				ref = head.Hash.String()
50			}
51
52			tree, err := r.LsTree(ref)
53			if err != nil {
54				return err
55			}
56
57			ents := git.Entries{}
58			if path != "" && path != "/" {
59				te, err := tree.TreeEntry(path)
60				if err == git.ErrRevisionNotExist {
61					return ErrFileNotFound
62				}
63				if err != nil {
64					return err
65				}
66				if te.Type() == "tree" {
67					tree, err = tree.SubTree(path)
68					if err != nil {
69						return err
70					}
71					ents, err = tree.Entries()
72					if err != nil {
73						return err
74					}
75				} else {
76					ents = append(ents, te)
77				}
78			} else {
79				ents, err = tree.Entries()
80				if err != nil {
81					return err
82				}
83			}
84			ents.Sort()
85			for _, ent := range ents {
86				size := ent.Size()
87				ssize := ""
88				if size == 0 {
89					ssize = "-"
90				} else {
91					ssize = humanize.Bytes(uint64(size))
92				}
93				cmd.Printf("%s\t%s\t %s\n", ent.Mode(), ssize, ent.Name())
94			}
95			return nil
96		},
97	}
98	return cmd
99}