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